Content-Disposition标头中的Unicode

时间:2010-03-30 07:52:20

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

我正在使用在HttpHandler子项中实现的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是没有用的。

即是'ß''ä''ö''ü''ó³''ß' 'ä''ö''ü'_'ó³'并且在Firefox中它是'Ã''''''''''''''''''''''' ''Ã'''''''''。

任何想法如何解决这个问题?

7 个答案:

答案 0 :(得分:16)

我有类似的问题。您必须使用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的引用,其中指出:

  

星号(“*”)被重复使用   语言和语言的指标   字符集信息存在   正在使用编码。单身   quote(“'”)用于分隔   字符集和语言信息   在参数的开头   值。百分号(“%”)用作   编码标志,同意   RFC 2047。

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

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

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

答案 1 :(得分:7)

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

答案 2 :(得分: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/

答案 3 :(得分:2)

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

答案 4 :(得分:1)

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

var result = new HttpResponseMessage(HttpStatusCode.OK)
{
   Content = new ByteArrayContent(data)
};

result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileNameStar = "foo-ä-€.html"
};

当我看到fiddler中的repsonse时,我可以看到文件名已经自动使用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/上使用了Testcases for Content-Disposition标头。 有关ContentDispositionHeaderValue类的信息可以在MSDN上找到。

答案 5 :(得分:0)

对于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());

答案 6 :(得分:0)

我使用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);