【问题标题】:How do I decode a URL and get the query string as a HashMap?如何解码 URL 并将查询字符串作为 HashMap 获取?
【发布时间】:2017-04-07 08:08:03
【问题描述】:

我有一个这样的网址:

http%3A%2F%2Fexample.com%3Fa%3D1%26b%3D2%26c%3D3

我用hyper::Url::parse 解析它并获取查询字符串:

let parsed_url = hyper::Url::parse(&u).unwrap();
let query_string = parsed_url.query();

但它给了我一个字符串的查询。我想获取查询字符串为HashMap。像这样:

// some code to convert query string to HashMap
hash_query.get(&"a"); // eq to 1
hash_query.get(&"b"); // eq to 2

【问题讨论】:

  • 应该输入http://example.com?a=1&b=2&c=3 代替吗?当它被这样编码时,它不是一个有效的 URL。
  • percent_decode lib 适用于完全编码的 URL,如 Saeed 的:http%3A%2F%2Fexample.com%3Fa%3D1%26b%3D2%26c%3D3

标签: rust query-string parse-url


【解决方案1】:

涉及几个步骤:

  • .query_pairs() 方法将为您提供一个迭代 Cow<str> 对的迭代器。

  • 调用 .into_owned() 会给你一个迭代器,而不是 String 对。

  • 这是(String, String) 的迭代器,正好是.collect()HashMap<String, String> 的正确形状。

把它放在一起:

use std::collections::HashMap;
let parsed_url = Url::parse("http://example.com/?a=1&b=2&c=3").unwrap();
let hash_query: HashMap<_, _> = parsed_url.query_pairs().into_owned().collect();
assert_eq!(hash_query.get("a"), "1");

请注意,您需要在 hash_query 上添加类型注释——因为 .collect() 已重载,您必须告诉编译器您想要哪种集合类型。

如果您需要处理重复或重复的键,请尝试multimap crate:

use multimap::MultiMap;
let parsed_url = Url::parse("http://example.com/?a=1&a=2&a=3").unwrap();
let hash_query: MultiMap<_, _> = parsed_url.query_pairs().into_owned().collect();
assert_eq!(hash_query.get_vec("a"), Some(&vec!["1", "2", "3"]));

【讨论】:

  • 请注意,这会覆盖重复的键。许多 Web 框架利用了您可以多次提交同一个密钥这一事实。
  • 请注意,如果您只有一个查询字符串,而不是完整的 URL,那么您可以改用 url::form_urlencoded::parse()
  • HashMap 类型从何而来?编辑:Neverming,它是::std::collections::HashMap
  • 有没有办法将重复/重复的键解析为数组?
  • @tworec 保留重复键,将HashMap&lt;_, _&gt; 更改为Vec&lt;_&gt;
【解决方案2】:

另一个答案很好,但我觉得这是应该更多的东西 直截了当,所以我将它包装在一个函数中:

use {
   std::collections::HashMap,
   url::Url
};

fn query(u: Url) -> HashMap<String, String> {
   u.query_pairs().into_owned().collect()
}

fn main() -> Result<(), url::ParseError> {
   let u = Url::parse("http://stackoverflow.com?month=May&day=Friday")?;
   let q = query(u);
   println!("{:?}", q);
   Ok(())
}

或者,我找到了另一个可以为您执行此操作的 crate:

use auris::URI;

fn main() -> Result<(), auris::ParseError> {
   let s = "http://stackoverflow.com?month=May&day=Friday";
   let u: URI<String> = s.parse()?;
   println!("{:?}", u.qs); // Some({"month": "May", "day": "Friday"})
   Ok(())
}

https://docs.rs/auris

【讨论】:

  • 关于auris,我有点怀疑没有存储库和依赖项的板条箱。这可能没问题,但我宁愿坚持使用更有信誉的包装。
猜你喜欢
  • 1970-01-01
  • 2011-10-21
  • 1970-01-01
  • 2016-09-25
  • 1970-01-01
  • 2012-04-27
  • 2014-06-29
  • 2012-11-21
  • 1970-01-01
相关资源
最近更新 更多