简体   繁体   English

HttpClient 在 Content-Disposition 中编码错误

[英]HttpClient wrong encoding in Content-Disposition

I am POST-ing an image with HttpClient and it works well for files with Latin names, but as soon as a name contains any non-ASCII characters it gets transformed to a sequence of question marks.我正在使用HttpClient POST 图像,它适用于具有拉丁名称的文件,但只要名称包含任何非 ASCII 字符,它就会转换为一系列问号。 If I create an html form and use a browser to post the file, the file name is sent in UTF8 and the target server perfectly accepts it.如果我创建一个 html 表单并使用浏览器发布文件,则文件名以 UTF8 格式发送,目标服务器完全接受它。

using (var client = new HttpClient())
{
    var streamContent = new StreamContent(someImageFileStream);
    streamContent.Headers.Add(
        "Content-Disposition",
        "form-data; name=\"image\"; filename=\"Тест.jpg\"");

    var content = new MultipartFormDataContent();
    content.Add(streamContent);

    await client.PostAsync("http://localhost.fiddler/", content);
}

This produces the following request:这会产生以下请求:

POST http://localhost/ HTTP/1.1
Content-Type: multipart/form-data; boundary="e6fe89be-e652-4fe3-8859-8c7a339c5550"
Host: localhost
Content-Length: 10556

--e6fe89be-e652-4fe3-8859-8c7a339c5550
Content-Disposition: form-data; name="image"; filename="????.jpg"

...here goes the contents of the file...

I understand that HttpClient might work according to some standard, but anyway, is there any workaround?我知道HttpClient可能会根据某些标准工作,但无论如何,有什么解决方法吗?

UPDATE : The external API doesn't want to accept the format filename*=utf-8''Тест.jpg , it expects filename="Тест.jpg" .更新:外部 API 不想接受filename*=utf-8''Тест.jpg格式,它需要filename="Тест.jpg"

OK, I've found a way to force MultipartFormDataContent to forget the ancient RFCs and use UTF8 instead.好的,我找到了一种方法来强制MultipartFormDataContent忘记古老的 RFC 并改用 UTF8。 The trick is to use reflection to overwrite the DefaultHttpEncoding defined in the internal static class HttpRuleParser .诀窍是使用反射来覆盖内部静态类HttpRuleParser定义的DefaultHttpEncoding

typeof(HttpClient)
  .Assembly
  .GetType("System.Net.Http.HttpRuleParser")
  .GetField("DefaultHttpEncoding", BindingFlags.Static | BindingFlags.NonPublic)
  .SetValue(null, System.Text.Encoding.UTF8);

Not sure which bad consequences that might cause, but I suppose there are none.不确定可能导致哪些不良后果,但我想没有。

This is another way to workaround the limitation of HttpClient without tampering with internal fields.这是在不篡改内部字段的情况下解决 HttpClient 限制的另一种方法。 Inspired by this answer .受到这个答案的启发。

using (var client = new HttpClient())
{
    var streamContent = new StreamContent(someImageFileStream);
    streamContent.Headers.Add("Content-Disposition",
        new string(Encoding.UTF8.GetBytes("form-data; name=\"image\"; filename=\"Тест.jpg\"").
        Select(b => (char)b).ToArray()));

    var content = new MultipartFormDataContent();
    content.Add(streamContent);
    await client.PostAsync("http://localhost.fiddler/", content);
}

I confirm that even .net core 2.2 doesn't have proper support for uploading files whose names contain non-ASCII characters.我确认即使 .net core 2.2 也不支持上传名称包含非 ASCII 字符的文件。 HttpClient does work according to some standard but Java servers don't care about that standard and expect UTF-8 formatted headers. HttpClient 确实根据一些标准工作,但 Java 服务器不关心该标准并期望 UTF-8 格式的标头。

Instead of adding a header that you built yourself, use the .NET library:不要添加您自己构建的标头,而是使用 .NET 库:

streamContent.Headers.ContentDisposition = 
    new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") { 
        Name = "image", 
        FileName = "Тест.jpg" };

That creates the header per the web docs and RFC5987 .这会根据Web 文档RFC5987创建标头。

Content-Disposition: form-data; name=image; filename="=?utf-8?B?0KLQtdGB0YIuanBn?="

If it helps, you can also remove the " filename *"如果有帮助,您还可以删除“文件名*”

//It deletes filename* parametr
foreach (var content in multipartContent) {
   var headerContent = content.Headers.ContentDisposition.Parameters.Where(x => x.Name == "filename*").SingleOrDefault();
   if(headerContent != null)
      content.Headers.ContentDisposition.Parameters.Remove(headerContent);
}
                            

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM