【问题标题】:Unicode in Content-Disposition headerContent-Disposition 标头中的 Unicode
【发布时间】:2011-02-02 08:51:26
【问题描述】:

我正在使用 HttpHandler child 中实现的 HttpContext 对象来下载文件,当我在文件名中有非 ascii 字符时,它在 IE 中看起来很奇怪,而在 Firefox 中看起来很好。

下面是代码:-

       context.Response.ContentType = ".cs";
context.Response.AppendHeader("Content-Length", data.Length.ToString());
context.Response.AppendHeader("Content-Disposition", String.Format("attachment; filename={0}",filename));
        context.Response.OutputStream.Write(data, 0, data.Length);

context.Response.Flush();

当我在文件名字段中提供 'ß' 'ä' 'ö' 'ü' 'ó' 'ß' 'ä' 'ö' 'ü' 'ó' 时,它看起来与我的不同在文件名中有它在Firefox中看起来很好。添加 EncodingType 和 charset 已经没有用了。

在ie中是'ß''ä''ö''ü''ó''ß' 'ä''ö''ü'_'ó' 在 Firefox 中是 'ß' 'ä' 'ö' 'ü' 'ó' 'ß' 'ä ' 'ö' 'ü' 'ó'。

知道如何解决这个问题吗?

【问题讨论】:

  • 这是文件的内容,还是文件名本身?
  • @leppie,它是文件名本身

标签: c# .net http-headers content-disposition


【解决方案1】:

我有类似的问题。您必须使用HttpUtility.UrlEncodeServer.UrlEncode 对文件名进行编码。我还记得Firefox不需要它。此外,它在 url 编码时破坏了文件名。我的代码:

// IE needs url encoding, FF doesn't support it, Google Chrome doesn't care
if (Request.Browser.IsBrowser ("IE"))
{
    fileName = Server.UrlEncode(fileName);
}

Response.Clear ();
Response.AddHeader ("content-disposition", String.Format ("attachment;filename=\"{0}\"", fileName));
Response.AddHeader ("Content-Length", data.Length.ToString (CultureInfo.InvariantCulture));
Response.ContentType = mimeType;
Response.BinaryWrite(data);

编辑

我已经更仔细地阅读了规范。首先RFC2183 声明:

当前 [RFC 2045] 语法将参数值(以及内容处置文件名)限制为 US-ASCII。

但后来我发现 [RFC 2045] 已过时,必须引用 RFC 2231,其中指出:

星号(“*”)被重复使用以提供 语言和指标 存在字符集信息 并且正在使用编码。一个 引号(“'”)用于分隔 字符集和语言信息 在参数的开头 价值。百分号 ("%") 用作 编码标志,它同意 RFC 2047。

这意味着您可以将 UrlEncode 用于非 ascii 符号,只要您包含 rfc 中所述的编码。这是一个例子:

string.Format("attachment; filename=\"{0}\"; filename*=UTF-8''{0}", Server.UrlEncode(fileName, Encoding.UTF8));

请注意,除了 filename* 之外,还包括 filename 以实现向后兼容性。您也可以选择其他编码并相应地修改参数,但 UTF-8 涵盖了所有内容。

【讨论】:

  • @Sergej,我试过你说的,它工作正常,你能解释一下为什么它破坏了文件名,这样我在实际实施之前就清楚了。
  • 根据 Ash 的回答,我使用了这个,但使用了 UrlPathEncode,这就像一个魅力(它不添加“+”号)。
  • 谢谢。我正在使用 Java 并使用 Guava 的 PercentageEncoder 对文件名进行编码:new PercentEscaper("_-", false).escape(filename)
【解决方案2】:

HttpUtility.UrlPathEncode 可能是更好的选择。由于 URLEncode 将用“+”号替换空格。

【讨论】:

    【解决方案3】:

    对我来说,这个解决方案适用于所有主流浏览器:

    Response.AppendHeader("Content-Disposition", string.Format("attachment; filename*=UTF-8''{0}", HttpUtility.UrlPathEncode(fileName).Replace(",", "%2C"));
    var mime = MimeMapping.GetMimeMapping(fileName);
    return File(fileName, mime);
    

    使用 ASP.NET MVC 3。

    替换是必要的,因为 Chrome 不喜欢在参数值中使用逗号 (,):http://www.gangarasa.com/lets-Do-GoodCode/tag/err_response_headers_multiple_content_disposition/

    【讨论】:

      【解决方案4】:

      您可能想阅读RFC 6266 并查看http://greenbytes.de/tech/tc2231/ 上的测试。

      【讨论】:

        【解决方案5】:

        对我来说,这解决了问题:

        var result = new HttpResponseMessage(HttpStatusCode.OK)
        {
           Content = new ByteArrayContent(data)
        };
        
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileNameStar = "foo-ä-€.html"
        };
        

        当我查看 fiddler 中的响应时,我可以看到文件名已自动使用 UTF-8 进行编码:

        Fiddler response example with encoded Content-Disposition filename using UTF-8

        如果我们查看 Content-Disposition 标头的值,我们可以看到它与@Johannes Geyer 他的答案相同。唯一的区别是我们不必自己进行编码,ContentDispositionHeaderValue 类负责处理。

        正如 Julian Reschke 所提到的,我在 http://greenbytes.de/tech/tc2231/ 上使用了 Content-Disposition 标头的测试用例。 有关 ContentDispositionHeaderValue 类的信息可以在 MSDN 上找到。

        【讨论】:

        • 我为 FileNameStar 编码了值。它不起作用。该框架已经很好地处理了编码。
        【解决方案6】:

        对于 Asp.Net Core(截至本文的第 2 版)UrlPathEncode 已弃用,以下是实现所需结果的方法:

        System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
        {
           FileName = Uri.EscapeUriString(fileName),
           Inline = true  // false = prompt the user for downloading;  true = browser to try to show the file inline
        };
        
        Response.Headers.Add("Content-Disposition", cd.ToString());
        

        【讨论】:

          【解决方案7】:

          我使用Uri.EscapeUriString 将所有字符转换为其十六进制表示,string.Normalize 用于 Unicode 规范化形式 C。 (在 ASP.NET MVC5 框架 4.5 中测试)

              var contentDispositionHeader = new System.Net.Mime.ContentDisposition
              {
                  Inline = false,
                  FileName = Uri.EscapeUriString(Path.GetFileName(pathFile)).Normalize()
              };
              Response.Headers.Add("Content-Disposition", contentDispositionHeader.ToString());
              string mimeType = MimeMapping.GetMimeMapping(Server.MapPath(pathFile));
              return File(file, mimeType);
          

          【讨论】:

            猜你喜欢
            • 2012-02-27
            • 2018-10-30
            • 1970-01-01
            • 2011-09-27
            • 2017-10-29
            • 2019-03-04
            • 1970-01-01
            • 2013-02-10
            相关资源
            最近更新 更多