如何在控制台应用程序中模拟Internet Explorer URL编码

时间:2018-05-08 01:08:05

标签: .net internet-explorer encoding

目标:

制作一个控制台应用程序,以完全正确的方式发送简单的获取请求。

问题:

我有这样的网址: http://myhost/somepage.do?Search01=コード番号=123456&Search02=改訂番号=2

当我将其复制并传递到IE 11或更低版本时,我想要的页面正确返回。 当我复制并将其复制到IE Edge,chrome,firefox时,它会返回一个错误,说它无法正确识别参数。

我用Wireshark对此进行了调查,我可以清楚地看到ol' IE正在使用某种不同的编码发送网址: enter image description here

Chrome可以执行更合理的编码: enter image description here

我不完全理解这里发生了什么,但似乎我发送消息的这台服务器,对于ol' IE浏览器搞乱了网址编码的方式 - 因为它只是回复了混乱的请求。

我已经检查了其他东西,如useragent等 - 它没有任何区别。该服务器正在运行一个非常旧的服务(可能使用ASP)。

所以,我的目标是在控制台应用程序中模拟这个混乱的编码。我该怎么做?

1 个答案:

答案 0 :(得分:1)

所以,在了解可能发生的事情的帮助下: This stackoverflow question

我开始意识到我的网址是如何被编码的。

我的电脑是日语,因此默认代码页是932。 在使用示例控制台应用程序并观察Wireshark中的数据包之后,我意识到无论我做了什么,默认的 HttpClientWebClient将始终正确地对我的URL进行UrlEncode 无论我使用什么编码。这不是'IE'如何编码它的URL。

我深入挖掘并发现HttpClient WebClient {和DontEscape}它使用了类in the source,它有一个带参数的构造函数:HttpClient我想,“Eurika!”但事实证明这个构造函数已经过时了,在使用WebClientTcpClient 时,没有办法让URL自动逃脱。

所以我不得不使用 /// <summary> /// The initial request to search only works if the url is encoded using Shift-JIS, which means we cannot use any client library and must use a custom TCP message. /// </summary> /// <param name="serveripaddress"></param> /// <param name="restoftheurl"></param> /// <returns></returns> private async Task<string> HttpRequestAsync(string serveripaddress, string restoftheurl) { Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); string result = string.Empty; using (var tcp = new TcpClient(serveripaddress, 80)) using (var stream = tcp.GetStream()) { tcp.SendTimeout = 500; tcp.ReceiveTimeout = 1000; Console.WriteLine("URL rest:" + restoftheurl); // Send request headers var builder = new StringBuilder(); builder.AppendLine("GET " + restoftheurl + " HTTP/1.1"); builder.AppendLine("Host: " + serveripaddress); //builder.AppendLine("Content-Length: " + data.Length); // only for POST request builder.AppendLine("Accept: text/html, application/xhtml+xml, */*"); builder.AppendLine("Accept-Language: ja-JP"); builder.AppendLine("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"); builder.AppendLine("Accept-Encoding: gzip, deflate"); builder.AppendLine("Connection: Close"); builder.AppendLine(); Console.WriteLine("Sending message:" + builder.ToString()); var header = Encoding.GetEncoding(932).GetBytes(builder.ToString()); await stream.WriteAsync(header, 0, header.Length); // Send payload data if you are POST request //await stream.WriteAsync(data, 0, data.Length); // receive data using (var memory = new MemoryStream()) { await stream.CopyToAsync(memory); memory.Position = 0; var data = memory.ToArray(); var index = BinaryMatch(data, Encoding.ASCII.GetBytes("\r\n\r\n")) + 4; var headers = Encoding.ASCII.GetString(data, 0, index); memory.Position = index; if (headers.IndexOf("Content-Encoding: gzip") > 0) { using (GZipStream decompressionStream = new GZipStream(memory, CompressionMode.Decompress)) using (var decompressedMemory = new MemoryStream()) { decompressionStream.CopyTo(decompressedMemory); decompressedMemory.Position = 0; result = Encoding.UTF8.GetString(decompressedMemory.ToArray()); } } else { result = Encoding.UTF8.GetString(data, index, data.Length - index); //result = Encoding.GetEncoding("gbk").GetString(data, index, data.Length - index); } } //Debug.WriteLine(result); return result; } } private int BinaryMatch(byte[] input, byte[] pattern) { int sLen = input.Length - pattern.Length + 1; for (int i = 0; i < sLen; ++i) { bool match = true; for (int j = 0; j < pattern.Length; ++j) { if (input[i + j] != pattern[j]) { match = false; break; } } if (match) { return i; } } return -1; } } 来代替我自己的请求。哪个Uri

var header = Encoding.GetEncoding(932).GetBytes(builder.ToString());

此代码的关键部分是:

<强> Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

这会强制在我的代码页中编码字符串,这需要注册代码页提供程序,因此在顶部: await HttpRequestAsync("123.456.789.123", "/somepage.do?Search01=コード番号=123456&Search02=改訂番号=2");

用法很简单:

https://play.google.com/store/account/subscriptions?sku=XXX&package=YYY