如何防止System.Uri解码URL

时间:2019-10-28 13:21:59

标签: c#

以这个例子为例:

var client = new HttpClient();
await client.GetAsync("http://www.google.com?q=%2D");

这实际上将请求发送到“ Aggregate Report”。我不想.NET更改我的网址。

此行为来自System.Uri,它似乎无法转义这些字符。

如何防止Uri / HttpClient更改我的网址?

.NET Framework 4.7.2

更新:此行为是设计使然。我仍然不敢相信没有办法解决这个问题。如果我实际上想向google.com发送“?q =%2D是什么意思”怎么办?现在,将其发送为“ http://www.google.com?q=-”。这不是我的本意。

1 个答案:

答案 0 :(得分:1)

基于反射的可能局部解决方案。

认为问题是-被列为特殊字符,在这里:https://referencesource.microsoft.com/#System/net/System/UriHelper.cs,657。我认为没有办法修改http方案来改变这种行为。

以前存在一个错误,此错误已得到修复,该错误与Uri解析文件路径有关。当时,解决方法是使用反射来更改相关UriParser的专用标志:https://stackoverflow.com/a/2285321/1462295

这是一个快速演示,您必须评估它是否有帮助。这取决于是调用uri.ToString()(然后可能会有所帮助)还是uri.GetComponents(然后您必须弄清楚其他事情)。这段代码到达Uri对象中,并将解析后的字符串替换为其他内容。这是代码和控制台输出:

static void Main(string[] args)
{
    var surl = "http://www.google.com?q=%2D";

    var url = new Uri(surl);
    Console.WriteLine("Broken: " + url.ToString());

    // Declared in Uri class as
    //     private UriInfo     m_Info;
    // https://referencesource.microsoft.com/#System/net/System/URI.cs,129
    FieldInfo infoField = url.GetType().GetField("m_Info", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

    // Immediately after m_Info is declared, the private class definition is given:
    //     private class UriInfo {
    //         public string   String;
    //         ...
    //     };
    object info = infoField.GetValue(url);
    FieldInfo infoStringField = info.GetType().GetField("String");

    // If you check the value of m_Info.String, you'll see it has the
    // modified string with '?q=-'.
    // The idea with this block of code is to replace the parsed
    // string with the one that you want.
    // This just replaces the string with the original value.
    infoStringField.SetValue(info, surl);

    // ToString() @ https://referencesource.microsoft.com/#System/net/System/URI.cs,1661
    // There are a couple of 'if' branches, but the last line is
    //     return m_Info.String;
    // This is the idea behind the above code.
    Console.WriteLine("Fixed: " + url.ToString());

    // However, GetComponents uses entirely different logic:
    Console.WriteLine($"Still broken: {url.GetComponents(UriComponents.AbsoluteUri, UriFormat.Unescaped)}");
    Console.WriteLine($"Still broken: {url.GetComponents(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped)}");
    Console.WriteLine($"Still broken: {url.GetComponents(UriComponents.AbsoluteUri, UriFormat.UriEscaped)}");

    Console.WriteLine("Press ENTER to exit ...");
    Console.ReadLine();
}

控制台输出:

Broken: http://www.google.com/?q=-
Fixed: http://www.google.com?q=%2D
Still broken: http://www.google.com/?q=-
Still broken: http://www.google.com/?q=-
Still broken: http://www.google.com/?q=-
Press ENTER to exit ...

您可能会从代码here中找到其他启发,​​该代码确实使用了反射,但是也定义了自己的使用方案。请注意提到的信任问题。

您提到了.Net Framework 4.7.2,它应与上述代码一起使用。 dotnet核心不会。