UriBuilder()。查询将错误地编码非ASCII字符

时间:2016-08-10 15:21:29

标签: c# asp.net .net asp.net-mvc http

我正在开发一个asp.net mvc 4 Web应用程序。我正在使用.net 4.5。现在我有以下WebClient()类:

using (var client = new WebClient())
{
    var query = HttpUtility.ParseQueryString(string.Empty);

    query["model"] = Model;
    //code goes here for other parameters....

    string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
    var url = new UriBuilder(apiurl);
    url.Query = query.ToString();

    string xml = client.DownloadString(url.ToString());
    XmlDocument doc = new XmlDocument();
    //code goes here ....

}

现在我注意到其中一个参数包含非ASCII租船人的问题,例如£¬等等。

现在最终查询将错误地编码任何非ASCII字符(例如£)(如%u00a3)。我读到了这个问题,似乎我可以取代: -

url.Query = query.ToString();

url.Query = ri.EscapeUriString(HttpUtility.UrlDecode(query.ToString()));    

现在使用后一种方法会将£编码为%C2%A3,这是正确的编码值。

但是我遇到url.Query = Uri.EscapeUriString(HttpUtility.UrlDecode(query.ToString()));的问题,在这种情况下,其中一个参数包含&,那么网址将具有以下格式&operation=AddAsset&assetName=&....,因此它会假设我传递为空assetName参数不是值= & ??

修改

让我再次总结一下我的问题。我希望能够将我的URL中的以下3项内容传递给第三方API:

  1. 标准字符,例如A,B,a,b,1,2,3 ......

  2. 非{ASCII}字符,例如£¬

  3. 以及网址编码中使用的特殊字符,例如&+

  4. 现在我尝试了以下两种方法:

    接近A

    using (var client = new WebClient())
    {
        var query = HttpUtility.ParseQueryString(string.Empty);
    
        query["model"] = Model;
        //code goes here for other parameters....
    
        string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
        var url = new UriBuilder(apiurl);
        url.Query = query.ToString();
    
        string xml = client.DownloadString(url.ToString());
        XmlDocument doc = new XmlDocument();
        //code goes here ....
    
    }
    

    在这种方法中,我可以传递诸如&+之类的值,因为它们将被url编码,但是如果我想传递非ASCII字符,它们将使用ISO-进行编码8859-1 ...如果我有£值,我的上述代码将编码为%u00a3,它将作为%u00a3而不是£保存在第三方API中}。

    方法B:

    我用:

    url.Query = Uri.EscapeUriString(HttpUtility.UrlDecode(query.ToString())); 
    

    而不是

    url.Query = query.ToString();
    

    现在我可以传递非{ASCII}字符,例如£,因为它们将使用UTF8而不是ISO-8859-1正确编码。但是我无法传递&之类的值,因为我的网址会被第三方API错误地读取..例如,如果我想传递assetName=&,我的网址将如下所示:

    &operation=Add&assetName=&
    

    所以第三部分API将假设我传递空assetName,而我正在尝试将其值传递为& ...

    所以不确定如何传递非{ASCII}字符+ &+等字符

5 个答案:

答案 0 :(得分:9)

您可以改用System.Net.Http.FormUrlEncodedContent

这适用于名称/值配对和词典的词典,与NameValueCollection不同,不会错误地#34;将£等字符映射到无用的转义(%u00a3,在您的情况下)。

相反,FormUrlEncodedContent可以在其构造函数中使用字典。当你读出它的字符串时,它将正确地对字典值进行urlencoded。

它将正确且统一地处理您遇到问题的两种情况:

  • £(超出urlencoding的字符值范围,需要编码为十六进制值才能传输)
  • &(正如您所说,它在url中具有作为参数分隔符的含义,因此值不能包含它 - 因此它也必须进行编码)。

这是一个代码示例,它显示您提到的各种示例项目(由item1,item2和item3表示)现在最终正确地urlencoded:

String item1 = "£";
String item2 = "&";
String item3 = "xyz";

Dictionary<string,string> queryDictionary = new Dictionary<string, string>()
{
    {"item1", item1},
    {"item2", item2},
    {"item3", item3}
};

var queryString = new System.Net.Http.FormUrlEncodedContent(queryDictionary)
        .ReadAsStringAsync().Result;

queryString将包含item1=%C2%A3&item2=%26&item3=xyz

答案 1 :(得分:3)

也许您可以尝试在Extension method课程中使用NameValueCollection。像这样:

using System.Collections.Specialized;
using System.Text;
using System.Web;

namespace Testing
{
    public static class NameValueCollectionExtension
    {
        public static string ToUtf8UrlEncodedQuery(this NameValueCollection nv)
        {
            StringBuilder sb = new StringBuilder();
            bool firstIteration = true;
            foreach (var key in nv.AllKeys)
            {
                if (!firstIteration)
                    sb.Append("&");
                sb.Append(HttpUtility.UrlEncode(key, Encoding.UTF8))
                    .Append("=")
                    .Append(HttpUtility.UrlEncode(nv[key], Encoding.UTF8));
                firstIteration = false;
            }
            return sb.ToString();
        }
    }
}

然后,在您的代码中,您可以执行此操作:

url.Query = query.ToUtf8UrlEncodedQuery();

请务必为您放置using课程的namespace添加NameValueCollectionExtension指令。

答案 2 :(得分:2)

这里的问题不是UriBuilder.Query,它是UriBuilder.ToString()。请阅读此处的文档:https://msdn.microsoft.com/en-us/library/system.uribuilder.tostring(v=vs.110).aspx。该属性定义为返回构建器的“显示字符串”,而不是有效编码的字符串。 Uri.ToString()有一个类似的问题,因为它没有执行正确的编码。

使用以下代码:url.Uri.AbsoluteUri,它将始终是正确编码的字符串。你不应该在进入构建器的过程中进行任何编码(这是它的目的之一,毕竟,正确编码事物)。

答案 3 :(得分:2)

您需要使用:

 System.Web.HttpUtility.UrlEncode(key)

将您的代码更改为:

using (var client = new WebClient())
{
    var query = HttpUtility.ParseQueryString(string.Empty);

    query["model"] = Model;
    //code goes here for other parameters....

    string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
    var url = new UriBuilder(apiurl);
    url.Query = HttpUtility.UrlEncode(query.ToString());

    string xml = client.DownloadString(url.ToString());
    XmlDocument doc = new XmlDocument();
    //code goes here ....

}

答案 4 :(得分:1)

如果没有任何帮助,那么只需在参数值

内手动转换那些有问题的字符
& to %26
+ to %2B
? to %3F