HttpClient.PostAsync 的字符编码问题

Posted

技术标签:

【中文标题】HttpClient.PostAsync 的字符编码问题【英文标题】:Character encoding problem with HttpClient.PostAsync 【发布时间】:2020-07-18 04:52:56 【问题描述】:

我们有一个旧版网络应用程序,可以在浏览器中手动运行。当我尝试在代码中使用 http 帖子使用相同的 Web 应用程序时,我得到一些土耳其语字符?。

我有以下代码来发布 http 帖子:

var httpClient = new HttpClient(); //static readonly in real code

var content = new StringContent("id_6=some text with Turkish characters öçşığüÖÇŞİĞÜ", Encoding.GetEncoding("ISO-8859-9"), "application/x-www-form-urlencoded");
var response = httpClient.PostAsync(url, content).Result; //I know this is not a good way, I'll focus on it later
var responseInString = response.Content.ReadAsStringAsync().Result;
File.WriteAllText("c:\\temp\\a.htm", responseInString);

Web 应用程序返回一个带有一些输入值的 html,包括我的代码发布的那些值。我的代码发布的表单值和使用我的值计算的表单值包含错误的土耳其语字符,而带有土耳其语字符的硬编码提交按钮看起来还不错。

网络应用程序将此 html(为简单起见已截断)返回到我的代码:

<!-- BELOW IS THE HARDCODED FORM FIELD WITH TURKISH CHARS OK! DISPLAYED AS: Programı Çağır -->
<input type="submit" value="Program&#305; &Ccedil;a&#287;&#305;r" name="j_id_jsp_262293626_16"/>

<!-- IRRELEVANT HTML REMOVED -->

<!-- BELOW IS THE OUTPUT FORM FIELD WITH CHAR ş BAD! DISPLAYED AS: some text with Turkish characters öç???üÖÇ???Ü -->
<input type="text" value="some text with Turkish characters &ouml;&ccedil;???&uuml;&Ouml;&Ccedil;???&Uuml;" id="id_2" name="id_2"/>

<!-- BELOW IS THE INPUT FORM FIELD WITH CHAR ş BAD! -->
<input type="text" value="some text with Turkish characters &ouml;&ccedil;???&uuml;&Ouml;&Ccedil;???&Uuml;" id="id_6" name="id_6" />

响应标头看起来不错:

有什么问题?

编辑:发布到sample form 的类似代码可以正常工作:

    static readonly HttpClient httpClient = new HttpClient();

    [TestMethod]
    public void TestHttpClientForTurkish()
    
        var data = new Dictionary<string, string>()
        
            "fname", "öçşığü" ,
            "lname", "ÖÇŞİĞÜ" 
        ;

        var content = new FormUrlEncodedContent(data);
        var response = httpClient.PostAsync("https://www.w3schools.com/action_page.php", content).Result;

        var responseInString = response.Content.ReadAsStringAsync().Result;
        Assert.IsTrue(responseInString.Contains("öçşığü") && responseInString.Contains("ÖÇŞİĞÜ"));
    

【问题讨论】:

&amp;Ccedil;, &amp;Aring; 是entities &amp;#305; 等是 html codes。当 html 被渲染时,这些实体将被替换为普通字符。 看起来像是两次实体化的文本。您可以查看 content 是否正确编码,例如string text = await content.ReadAsStringAsync() 顺便说一句,显示的代码和输出不匹配。您能否展示可重现的示例,例如确切的代码和输出的确切部分?您可以使用带有async Task Main 的空白控制台应用程序,以便能够在那里使用await。请编辑问题。 var responseInString = response.Content.ReadAsStreamAsync().Result; 【参考方案1】:

我的发现:

    FormUrlEncodedContent 类不支持 Encoding 参数(因此不能处理土耳其字符),所以我不得不使用 StringContent 我必须使用 HttpUtility.UrlEncode 对表单值进行编码(并使用 ISO-8859-9 作为编码)。

以下是表单字段中土耳其语字符没有任何问题的最终代码:

var httpClient = new HttpClient(); //static readonly in real code
var iso = Encoding.GetEncoding("ISO-8859-9");

var content = new StringContent("id_6="+
    HttpUtility.UrlEncode("some text with Turkish characters öçşığüÖÇŞİĞÜ", iso), iso, 
    "application/x-www-form-urlencoded");
var response = httpClient.PostAsync(url, content).Result;//Using Result because I don't have a UI thread or the context is not ASP.NET
var responseInString = response.Content.ReadAsStringAsync().Result;
File.WriteAllText("c:\\temp\\a.htm", responseInString);

【讨论】:

【参考方案2】:

试试下面的代码

public static async Task SendRequestAsync()
        

            var data = new Dictionary<string, byte[]>();
            var key1 = "fname";

            var val1 = Encoding.Unicode.GetBytes("öçşığü");
            data.Add(key1, val1);

            var key2 = "lname";

            var val2 = Encoding.Unicode.GetBytes("ÖÇŞİĞÜ");
            data.Add(key2, val2);
            MemoryStream fs = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(fs, data);
            var barr = fs.ToArray();
            var client = new HttpClient
                
                    BaseAddress = new Uri("http://www.yourservicelocation.com")
                ;

                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(
                        new MediaTypeWithQualityHeaderValue("application/bson"));
            
                var byteArrayContent = new ByteArrayContent(barr);
                byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("application/bson");

                var result = await client.PostAsync(
                        "api/SomeData/Incoming", byteArrayContent);

                result.EnsureSuccessStatusCode();
            
        

【讨论】:

感谢您的回复。无论我使用您的代码发布什么内容,我们的服务都会返回主页。我猜它不支持此代码发送的内容。我会在这方面做更多的工作。 你必须在 api var val1 = Encoding.Unicode.GetBytes("öçşığü");其他明智的不要对此进行编码。整个对象在这里编码 我无法在服务器端进行任何更改,我没有它的代码。请记住,服务器端可以正常使用 chrome。

以上是关于HttpClient.PostAsync 的字符编码问题的主要内容,如果未能解决你的问题,请参考以下文章

如何正确使用 HttpClient PostAsync 参数?

带有json字符串的后台任务中的UWP Httpclient postasync

异步等待 HttpClient.PostAsync 调用

查看 HttpClient.PostAsync 的响应正文

HttpClient.PostAsync 崩溃应用。如何捕捉异常?

如何使用 HttpClient.PostAsync 发送 XML 内容?