.NET(C#): 解析和创建URL中的Query String
.NET(C#): 解析和创建URL中的Query String
2012年07月11日 ⁄ 综合 ⁄ 共 3538字 ⁄ 字号 小 中 大 ⁄ 评论关闭
工程中需要解析和构造URL中的Query String,客户端,自然用不到ASP.NET,也不想用什么第三方类库。自己写一个。
当然.NET 4.5中的FormUrlEncodedContent可以快速构建一个Query String数据,它继承自HttpContent,主要用来设置HTTP包的内容。
来用FormUrlEncodedContent创建一个简单的Query String:
//+ using System.Net.Http;
var data = new Dictionary<string, string>() { { "q", "一二三 Mgen" }, { "output", "search" } };
var content = new FormUrlEncodedContent(data);
Console.WriteLine(await content.ReadAsStringAsync());
输出:
q=%E4%B8%80%E4%BA%8C%E4%B8%89+Mgen&output=search
FormUrlEncodedContent会用到Uri.EsacapeDataString但是会把%20替换成+。
不过一个简单的Query String自然也不需要把代码要求提升到.NET 4.5。后来又写了两个方法,使用DataToUrl和UrlToData可以实现完整的带Query String的转换和创建。
方法使用IEnumerable<KeyValuePair<string, string>>做参数数据,和FormUrlEncodedContent保持一致,方便用户使用Dictionary<string, string>。
示例代码:
//URL数据
var data = new Dictionary<string, string>() { { "q", "一二三 Mgen" }, { "output", "search" } };
//编码
var str = DataToUrl("http://www.google.com", data);
Console.WriteLine("编码");
Console.WriteLine(str);
//解码
Console.WriteLine("解码");
var decoded = UrlToData(str);
Console.WriteLine(decoded.Item1);
Console.WriteLine(String.Join("\n", decoded.Item2));
输出:
编码
http://www.google.com?q=%E4%B8%80%E4%BA%8C%E4%B8%89%20Mgen&output=search
解码
http://www.google.com
[q, 一二三 Mgen]
[output, search]
当然程序还考虑到一些特殊情况,比如某些Query String有些不规则,如Google的查询可能会出现如下地址:
有?hl=en还有#hl=en。这个#应该是URL中跳转到HTML中链接位置,不属于Query String中的,Query String中应该对#进行编码,但是既然#出现在Google查询的参数中,那么程序只能去调节算法。一些Query String解析代码遇到此类URL要么挂掉要么显示:tab = ww#hl(我猜想是因为解析数据是按照=分割字符串,然后取前两个值,但是这里还多个”=en”,所以他就被忽略了)。至于该不该把#hl=en也解析出来,我认为不应该,毕竟他不符合URL Query String参数的格式。但是也不该把他忽略掉,解析不了就把原始值显示出来。
那么使用我的方法解析这种URL:
var url = "http://www.google.com/webhp?hl=en&tab=ww#hl=en&newwindow=1
&output=search&sclient=psy-ab&q=mgen&oq=mgen&gs_l=hp.3..0l4.6238.6514
.0.6788.4.4.0.0.0.0.171.481.1j3.4.0.les%3B..0.0...1c.1.n1GMg7Ow5KA&pb
x=1&bav=on.2,or.r_gc.r_pw.r_qf.&fp=5b519d645da47f94&biw=1241&bih=606";
var decoded = UrlToData(url);
Console.WriteLine(decoded.Item1);
Console.WriteLine(String.Join("\n", decoded.Item2));
结果:
http://www.google.com/webhp
[hl, en]
[tab, ww#hl=en]
[newwindow, 1]
[output, search]
[sclient, psy-ab]
[q, mgen]
[oq, mgen]
[gs_l, hp.3..0l4.6238.6514.0.6788.4.4.0.0.0.0.171.481.1j3.4.0.les;..0.0...1c.1.n
1GMg7Ow5KA]
[pbx, 1]
[bav, on.2,or.r_gc.r_pw.r_qf.]
[fp, 5b519d645da47f94]
[biw, 1241]
[bih, 606]
最后,方法源代码:
//编码
static string DataToUrl(string url, IEnumerable<KeyValuePair<string, string>> data)
{
if (data == null)
throw new ArgumentNullException("data");
bool first = true;
var sb = new StringBuilder(url);
foreach (var item in data)
{
if (first)
{
sb.Append('?');
first = false;
}
else
sb.Append('&');
sb.Append(Uri.EscapeDataString(item.Key) + "=" + Uri.EscapeDataString(item.Value));
}
return sb.ToString();
}
//解码
static Tuple<string, IEnumerable<KeyValuePair<string, string>>> UrlToData(string url)
{
if (url == null)
throw new ArgumentNullException("url");
url = url.Trim();
try
{
var split = url.Split(new[] { '?', '&' }, StringSplitOptions.RemoveEmptyEntries);
if (split.Length == 1)
return new Tuple<string, IEnumerable<KeyValuePair<string, string>>>(url, null);
//获取前面的URL地址
var host = split[0];
var pairs = split.Skip(1).Select(s =>
{
//没有用String.Split防止某些少见Query String中出现多个=,要把后面的无法处理的=全部显示出来
var idx = s.IndexOf('=');
return new KeyValuePair<string, string>(Uri.UnescapeDataString(s.Substring(0, idx)),Uri.UnescapeDataString(s.Substring(idx + 1)));
}).ToList();
return new Tuple<string, IEnumerable<KeyValuePair<string, string>>>(host, pairs);
}
catch (Exception ex)
{
throw new FormatException("URL格式错误", ex);
}
}
转载:http://www.xuebuyuan.com/130990.html

浙公网安备 33010602011771号