我知道我可以做到这个
var nv = HttpUtility.ParseQueryString(req.RawUrl);
但是有没有办法将它转换回URL呢?
var newUrl = HttpUtility.Something("/page", nv);
我知道我可以做到这个
var nv = HttpUtility.ParseQueryString(req.RawUrl);
但是有没有办法将它转换回URL呢?
var newUrl = HttpUtility.Something("/page", nv);
仅仅在NameValueCollection
上调用ToString()
将会以name1=value1&name2=value2
的查询字符串格式返回名称值对。请注意,NameValueCollection
类型实际上不支持此操作,并且建议这样做是具有误导性的,但由于实际返回的内部类型所以这里可以工作,如下所述。
感谢@mjwills指出HttpUtility.ParseQueryString
方法实际上返回的是一个内部的HttpValueCollection
对象而不是一个常规的NameValueCollection
(尽管文档指定为NameValueCollection
)。当使用ToString()
时,HttpValueCollection
会自动编码查询字符串,因此无需编写循环遍历集合并使用UrlEncode
方法的程序。期望的结果已经返回。
有了结果,您就可以将其附加到URL并重定向:
var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString());
string url = Request.Url.AbsolutePath + "?" + nameValues.ToString();
Response.Redirect(url);
目前使用HttpValueCollection
的唯一方法是使用上面展示的ParseQueryString
方法(当然除了反射)。看起来这不会改变,因为连接问题请求使该类变为公共类已经关闭,并标记为“不修复”。
另外,您可以调用nameValues
上的Add
、Set
和Remove
方法,在附加之前修改任何查询字符串项。如果您对此感兴趣请参阅我对另一个问题的回答。
string q = String.Join("&",
nvc.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(nvc[a])));
NameValueCollections
字面问题的选项,而不是提供的涉及 HttpValueCollection
的场景。 - drzausstring q = String.Join("&", nvc.AllKeys.Select(a => HttpUtility.UrlEncode(a) + "=" + HttpUtility.UrlEncode(nvc[a])));
- SoftDev编写一个扩展方法,使用一些循环。我更喜欢这个解决方案,因为它易于阅读(没有Linq),不需要System.Web.HttpUtility,并支持重复的键。
public static string ToQueryString(this NameValueCollection nvc)
{
if (nvc == null) return string.Empty;
StringBuilder sb = new StringBuilder();
foreach (string key in nvc.Keys)
{
if (string.IsNullOrWhiteSpace(key)) continue;
string[] values = nvc.GetValues(key);
if (values == null) continue;
foreach (string value in values)
{
sb.Append(sb.Length == 0 ? "?" : "&");
sb.AppendFormat("{0}={1}", Uri.EscapeDataString(key), Uri.EscapeDataString(value));
}
}
return sb.ToString();
}
var queryParams = new NameValueCollection()
{
{ "order_id", "0000" },
{ "item_id", "1111" },
{ "item_id", "2222" },
{ null, "skip entry with null key" },
{ "needs escaping", "special chars ? = &" },
{ "skip entry with null value", null }
};
Console.WriteLine(queryParams.ToQueryString());
?order_id=0000&item_id=1111&item_id=2222&needs%20escaping=special%20chars%20%3F%20%3D%20%26
这应该可以不需要太多代码就能工作:
NameValueCollection nameValues = HttpUtility.ParseQueryString(String.Empty);
nameValues.Add(Request.QueryString);
// modify nameValues if desired
var newUrl = "/page?" + nameValues;
这个想法是使用HttpUtility.ParseQueryString
生成一个空的HttpValueCollection
类型集合。该类是NameValueCollection
的子类,被标记为internal
,因此您的代码不能轻易创建它的实例。
HttpValueCollection
的好处在于ToString
方法会自动处理编码。通过利用NameValueCollection.Add(NameValueCollection)
方法,可以将现有的查询字符串参数添加到新创建的对象中,而无需先将Request.QueryString
集合转换为url编码的字符串,然后再解析回集合。
这种技术也可以作为扩展方法公开:
public static string ToQueryString(this NameValueCollection nameValueCollection)
{
NameValueCollection httpValueCollection = HttpUtility.ParseQueryString(String.Empty);
httpValueCollection.Add(nameValueCollection);
return httpValueCollection.ToString();
}
实际上,您应该对键进行编码,而不仅仅是值。
string q = String.Join("&",
nvc.AllKeys.Select(a => $"{HttpUtility.UrlEncode(a)}={HttpUtility.UrlEncode(nvc[a])}"));
因为NameValueCollection
可以有多个相同键的值,如果您关心查询字符串的格式(因为它将作为逗号分隔的值返回而不是“数组表示法”),您可以考虑以下内容。
var nvc = new NameValueCollection();
nvc.Add("key1", "val1");
nvc.Add("key2", "val2");
nvc.Add("empty", null);
nvc.Add("key2", "val2b");
将其转换为:key1=val1&key2[]=val2&empty&key2[]=val2b
而不是key1=val1&key2=val2,val2b&empty
。
string qs = string.Join("&",
// "loop" the keys
nvc.AllKeys.SelectMany(k => {
// "loop" the values
var values = nvc.GetValues(k);
if(values == null) return new[]{ k };
return nvc.GetValues(k).Select( (v,i) =>
// 'gracefully' handle formatting
// when there's 1 or more values
string.Format(
values.Length > 1
// pick your array format: k[i]=v or k[]=v, etc
? "{0}[]={1}"
: "{0}={1}"
, k, HttpUtility.UrlEncode(v), i)
);
})
);
如果你不是很喜欢Linq...
string qs = nvc.ToQueryString(); // using...
public static class UrlExtensions {
public static string ToQueryString(this NameValueCollection nvc) {
return string.Join("&", nvc.GetUrlList());
}
public static IEnumerable<string> GetUrlList(this NameValueCollection nvc) {
foreach(var k in nvc.AllKeys) {
var values = nvc.GetValues(k);
if(values == null) { yield return k; continue; }
for(int i = 0; i < values.Length; i++) {
yield return
// 'gracefully' handle formatting
// when there's 1 or more values
string.Format(
values.Length > 1
// pick your array format: k[i]=v or k[]=v, etc
? "{0}[]={1}"
: "{0}={1}"
, k, HttpUtility.UrlEncode(values[i]), i);
}
}
}
}
正如评论中已经指出的那样,除了这个答案之外,其他大多数答案都是针对场景进行处理(Request.QueryString
是一个HttpValueCollection
,而不是一个NameValueCollection
),而非字面上的问题。
更新:解决了评论中提到的空值问题。
NameValueCollection
上使用 .ToString()
并将其与原始 URL 组合起来。Request.RawUrl
上使用 HttpUtility.ParseQueryString
。 ParseQueryString()
方法正在寻找这样的值:?var=value&var2=value2
。QueryString
参数的 NameValueCollection
,只需使用 Request.QueryString()
。var nv = Request.QueryString;
string url = String.Format("{0}?{1}", Request.Path, nv.ToString());
如果您想解析URL字符串而不是使用Request
对象,请使用Uri
和HttpUtility.ParseQueryString
方法。
Uri uri = new Uri("<THE URL>");
var nv = HttpUtility.ParseQueryString(uri.Query);
string url = String.Format("{0}?{1}", uri.AbsolutePath, nv.ToString());
Request.QueryString
实际上不是一个NameValueCollection
,而是一个特殊的派生类HttpValueCollection
,这就是为什么.ToString
可以使用的原因;对于常规的nvc,您需要使用类似于此答案中提供的方法。 - drzausvar url = "http://my-link.com?foo=bar";
var uriBuilder = new UriBuilder(url);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query.Add("yep", "foo&bar");
uriBuilder.Query = query.ToString();
var result = uriBuilder.ToString();
// http://my-link.com:80/?foo=bar&yep=foo%26bar
正如@Atchitutchuk所建议的那样,您可以在ASP.NET Core中使用QueryHelpers.AddQueryString:
public string FormatParameters(NameValueCollection parameters)
{
var queryString = "";
foreach (var key in parameters.AllKeys)
{
foreach (var value in parameters.GetValues(key))
{
queryString = QueryHelpers.AddQueryString(queryString, key, value);
}
};
return queryString.TrimStart('?');
}
NameValueCollection.ToString()
方法返回的是System.Collections.Specialized.NameValueCollection
字符串(确切地说),而不是“准备格式化为查询字符串的名称值对”。请注意不改变原意,简明扼要。 - Igor Brejc