网络应用程序,希望以武力资源 下载 而不是直接 呈现 在一个网络浏览器问题的一个 Content-Disposition 头在HTTP响应的形式:

Content-Disposition: attachment; filename=文件名

filename 参数可用来表明文件的名称其资源被下载通过浏览器。 RFC2183 (Content-Disposition),但是,国 2.3节 (名参数),文件名称只能使用US-ASCII characters:

目前[RFC2045]法限制 参数的价值(因 Content-Disposition文件)来 US-ASCII.我们认识到伟大的 是否应允许任意 字符集在文件名,但是它是 超出了本文件的范围, 定义的必要机制。

有经验证据,尽管如此,最受欢迎的网络浏览器今天似乎允许non-US-ASCII characters但(为缺乏标准)不同意编码方案和特定规范的文件名称。问题是,什么是各种计划和编码中采用的流行浏览器,如果该文件名称"naïvefile"(没有报价,并在第三封信是U+00EF)需要编入Content-Disposition header?

对于这个问题的目的, 受欢迎的浏览器 正:

  • Firefox
  • Internet Explorer
  • Safari
  • 谷歌铬
  • 歌剧
有帮助吗?

解决方案

没有讨论这个,包括链接浏览器测试和向后兼容,在拟议 RFC5987立方, "人物设置和语言编码文本传输协议(HTTP)标题领域的参数"。

RFC2183 表明这样的标题应该编码的根据 RFC2184, ,这是废弃的 RFC2231, 复盖草案RFC以上。

其他提示

我知道这是一个古老的职位,但它仍然是非常相关的。我们发现,现代浏览器支持rfc5987,它允许utf-8编码、编码的百分比(url-编码)。那么天真file.txt 变成:

Content-Disposition: attachment; filename*=UTF-8''Na%C3%AFve%20file.txt

Safari(5)不支持这一点。而不是你应该使用野生动物标准编写的文件名称直接在你的utf-8编码头:

Content-Disposition: attachment; filename=Naïve file.txt

IE8和年长不支持它,你要使用即标准的utf-8编码,百分比编码:

Content-Disposition: attachment; filename=Na%C3%AFve%20file.txt

在ASP.Net 我使用了下列代码:

string contentDisposition;
if (Request.Browser.Browser == "IE" && (Request.Browser.Version == "7.0" || Request.Browser.Version == "8.0"))
    contentDisposition = "attachment; filename=" + Uri.EscapeDataString(fileName);
else if (Request.Browser.Browser == "Safari")
    contentDisposition = "attachment; filename=" + fileName;
else
    contentDisposition = "attachment; filename*=UTF-8''" + Uri.EscapeDataString(fileName);
Response.AddHeader("Content-Disposition", contentDisposition);

我测试以上使用IE7,IE8,IE9、铬13、歌剧11,FF5,Safari5.

更新 日2013年:

这里是代码我目前使用的。我仍然必须支持IE8,所以我无法摆脱的第一部分。事实证明,浏览器上安卓的使用建立在安卓载管理,它无法可靠地分析文件的名称,在标准方式。

string contentDisposition;
if (Request.Browser.Browser == "IE" && (Request.Browser.Version == "7.0" || Request.Browser.Version == "8.0"))
    contentDisposition = "attachment; filename=" + Uri.EscapeDataString(fileName);
else if (Request.UserAgent != null && Request.UserAgent.ToLowerInvariant().Contains("android")) // android built-in download manager (all browsers on android)
    contentDisposition = "attachment; filename=\"" + MakeAndroidSafeFileName(fileName) + "\"";
else
    contentDisposition = "attachment; filename=\"" + fileName + "\"; filename*=UTF-8''" + Uri.EscapeDataString(fileName);
Response.AddHeader("Content-Disposition", contentDisposition);

上述现在进行测试IE7-11、铬32、歌剧12,FF25,Safari6,使用这个文件下载:你好abcABCæøåÆØÅäöüïëêîâéíáóúýñ½§!#¤%&()=`@£$€{[]}+^~'-_,;.txt

在IE7它适用于某些人物但不是全部。但是谁在乎IE7今天?

这是我的使用产生安全的文件名称序。注意,我不知道哪些人物都支持安卓,但我已经测试这些工作肯定的:

private static readonly Dictionary<char, char> AndroidAllowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-+,@£$€!½§~'=()[]{}0123456789".ToDictionary(c => c);
private string MakeAndroidSafeFileName(string fileName)
{
    char[] newFileName = fileName.ToCharArray();
    for (int i = 0; i < newFileName.Length; i++)
    {
        if (!AndroidAllowedChars.ContainsKey(newFileName[i]))
            newFileName[i] = '_';
    }
    return new string(newFileName);
}

@这:我测试了在IE7和IE8和事实证明,我不需要逃脱撇号(')。你有一个例子,它失败?

@Dave Van den Eynde:结合这两个文件上的姓名一行为根据RFC6266工作除和IE7+8和我已经更新了代码,以反映这一点。谢谢你的建议。

@蒂:不知道GoodReader或任何其他非浏览器。你可能会有一些幸运的使用的方法。

@亚历克斯茹科夫斯基:我不知道为什么但如上讨论过 连接 它似乎没有工作非常好。

有一个简单和非常棒的选择: 使用一个网址,包含该文件你想要的.

当名称之后的最后一削减是一个你想要的,你不需要任何额外头!

这一招的工作:

/real_script.php/fake_filename.doc

如果你的服务器支持网址的改写(例如 mod_rewrite 在Apache)然后,你可以完全隐藏的剧本的一部分。

字符的Url应在UTF-8,urlencoded逐字节:

/mot%C3%B6rhead   # motörhead

RFC6266 描述了"使用的Content-Disposition Header领域中的超文本传输协议(HTTP)".引用于:

6.国际化考虑因素

该"filename*"参数(4.3节),使用的编码的定义 在[RFC5987],允许服务器发射人物之外的 ISO-8859-1的字符组,并且还可选择指定的语言 在使用。

并在他们的 例部分:

这个例子是同一个以上,但添加"filename" 参数的相容性与用户代理不行 RFC5987立方:

Content-Disposition: attachment;
                     filename="EURO rates";
                     filename*=utf-8''%e2%82%ac%20rates

注:这些用户代理不支持 RFC5987立方 编码 忽视"filename*"当它发生后"filename”.

附录D 还有一个长长的清单的建议,增加互操作性。它还指在 一个网站,其比较实现.目前所有通过测试适用于共同文件名称中包括:

  • attwithisofnplain:纯ISO-8859-1文件中的名称与双引号中并没有编码。这就要求文件的名称是所有的ISO-8859-1和不包含%的迹象,至少不会在前六个数字。
  • attfnboth:两个参数以上所述。应工作对于大多数文件上的姓名最浏览器,虽然IE8会使用的"filename"参数。

RFC5987立方 反过来引用 RFC2231, ,其中描述了实际的格式。2231主要是用于邮寄,并5987立方告诉我们哪些部分可能被用于HTTP头。不要混淆这MIME header内部使用 multipart/form-data HTTP 身体, ,这是由 RFC2388 (第4.4节 特别是)和 HTML5草案.

以下文件的链接 草案RFC 提到过 吉姆 在他的回答进一步解决问题和绝对值得一直注意在这里:

测试案件,为HTTP Content-Disposition header和RFC2231/2047编码

在asp.net mvc2我用这样的事情:

return File(
    tempFile
    , "application/octet-stream"
    , HttpUtility.UrlPathEncode(fileName)
    );

我猜如果你不使用视(2)你可以只进行编码使用的文件名

HttpUtility.UrlPathEncode(fileName)

把文件名称中的双引号。解决了这个问题对于我。是这样的:

Content-Disposition: attachment; filename="My Report.doc"

http://kb.mozillazine.org/Filenames_with_spaces_are_truncated_upon_download

我已经测试了多种选择。浏览器不支持规范和不同的行为,我相信双引号是最好的选择。

我使用了下列代码段用于编码(假设 文件名 包含的文件和扩展的文件,即:test.txt):


PHP:

if ( strpos ( $_SERVER [ 'HTTP_USER_AGENT' ], "MSIE" ) > 0 )
{
     header ( 'Content-Disposition: attachment; filename="' . rawurlencode ( $fileName ) . '"' );
}
else
{
     header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode ( $fileName ) );
}

Java:

fileName = request.getHeader ( "user-agent" ).contains ( "MSIE" ) ? URLEncoder.encode ( fileName, "utf-8") : MimeUtility.encodeWord ( fileName );
response.setHeader ( "Content-disposition", "attachment; filename=\"" + fileName + "\"");

在ASP.NET 网API,我url编码filename:

public static class HttpRequestMessageExtensions
{
    public static HttpResponseMessage CreateFileResponse(this HttpRequestMessage request, byte[] data, string filename, string mediaType)
    {
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
        var stream = new MemoryStream(data);
        stream.Position = 0;

        response.Content = new StreamContent(stream);

        response.Content.Headers.ContentType = 
            new MediaTypeHeaderValue(mediaType);

        // URL-Encode filename
        // Fixes behavior in IE, that filenames with non US-ASCII characters
        // stay correct (not "_utf-8_.......=_=").
        var encodedFilename = HttpUtility.UrlEncode(filename, Encoding.UTF8);

        response.Content.Headers.ContentDisposition =
            new ContentDispositionHeaderValue("attachment") { FileName = encodedFilename };
        return response;
    }
}

IE 9 Not fixed
IE 9 Fixed

我测试了下列代码,在所有主要的浏览器,包括老年探险者(通过的兼容性模式),它工作得很好到处:

$filename = $_GET['file']; //this string from $_GET is already decoded
if (strstr($_SERVER['HTTP_USER_AGENT'],"MSIE"))
  $filename = rawurlencode($filename);
header('Content-Disposition: attachment; filename="'.$filename.'"');

如果您使用的是一个node.js后你可以用下面的代码,我发现 在这里,

var fileName = 'my file(2).txt';
var header = "Content-Disposition: attachment; filename*=UTF-8''" 
             + encodeRFC5987ValueChars(fileName);

function encodeRFC5987ValueChars (str) {
    return encodeURIComponent(str).
        // Note that although RFC3986 reserves "!", RFC5987 does not,
        // so we do not need to escape it
        replace(/['()]/g, escape). // i.e., %27 %28 %29
        replace(/\*/g, '%2A').
            // The following are not required for percent-encoding per RFC5987, 
            // so we can allow for a little better readability over the wire: |`^
            replace(/%(?:7C|60|5E)/g, unescape);
}

我结束了下列代码在我的"download.php"脚本(根据 该博文这些试验案例).

$il1_filename = utf8_decode($filename);
$to_underscore = "\"\\#*;:|<>/?";
$safe_filename = strtr($il1_filename, $to_underscore, str_repeat("_", strlen($to_underscore)));

header("Content-Disposition: attachment; filename=\"$safe_filename\""
.( $safe_filename === $filename ? "" : "; filename*=UTF-8''".rawurlencode($filename) ));

这种使用的标准方法filename="..."只要有只异latin1和"安全"字的使用;如果没有,它增加了该文件*=UTF-8"网址的编码的方式。根据 这一特定情况下测试, 它应该从MSIE9,并在最近FF、铬、野生动物园;在下MSIE版本,它应该提供的文件包含ISO8859-1版本的文件,强调在符不在这个编码。

最后的注:最大。大小的每个标题领域是8190字节apache.UTF-8可以将多达四个字每个字符;后rawurlencode,它是x3=12个字节每一个字符。漂亮的效率不高,但它仍然应该理论上可能有600多个"微笑"%F0%9%98%81的文件。

在PHP这没有对我的(假定该文件是UTF8编码):

header('Content-Disposition: attachment;'
    . 'filename="' . addslashes(utf8_decode($filename)) . '";'
    . 'filename*=utf-8\'\'' . rawurlencode($filename));

测试对IE8-11,火狐和铬。
如果浏览器可以解释 文件*=utf-8 它将使用UTF8版本的文件,否则它会使用解码文件。如果你的文件中包含的字符,不可表示在ISO-8859-1你可能想要考虑使用 iconv 代替。

经典ASP解决方案

大多数现代浏览器支持通过 Filename 作为 UTF-8 但现在就是这种情况的文件上载解决方案我用的是基于 FreeASPUpload.Net (站点不再存在,链接点 archive.org) 它不会的工作为分析的二进制依赖于阅读的单字节ASCII encoded strings,它工作得很好,当您通过了UTF-8编码数据的数据直到你得到符ASCII不支持。

但是我能找到一个解决方案得到代码阅读和分析的二进制as UTF-8.

Public Function BytesToString(bytes)    'UTF-8..
  Dim bslen
  Dim i, k , N 
  Dim b , count 
  Dim str

  bslen = LenB(bytes)
  str=""

  i = 0
  Do While i < bslen
    b = AscB(MidB(bytes,i+1,1))

    If (b And &HFC) = &HFC Then
      count = 6
      N = b And &H1
    ElseIf (b And &HF8) = &HF8 Then
      count = 5
      N = b And &H3
    ElseIf (b And &HF0) = &HF0 Then
      count = 4
      N = b And &H7
    ElseIf (b And &HE0) = &HE0 Then
      count = 3
      N = b And &HF
    ElseIf (b And &HC0) = &HC0 Then
      count = 2
      N = b And &H1F
    Else
      count = 1
      str = str & Chr(b)
    End If

    If i + count - 1 > bslen Then
      str = str&"?"
      Exit Do
    End If

    If count>1 then
      For k = 1 To count - 1
        b = AscB(MidB(bytes,i+k+1,1))
        N = N * &H40 + (b And &H3F)
      Next
      str = str & ChrW(N)
    End If
    i = i + count
  Loop

  BytesToString = str
End Function

信用去 纯ASP文件上传 通过实施 BytesToString() 从功能 include_aspuploader.asp 在我自己的代码我能得到 UTF-8 文件名工作。


有用的链接

只是一个更新,因为我是试图在所有这些东西今天在应对客户问题

  • 除野生动物园配置用于日本的,所有的浏览器我们的客户进行测试工作最好与filename=文本。pdf-中文本是一个客户的价值序列化ASP.Net/IIS 在utf-8没有url编码。由于某些原因,野生动物构成为英国将接受并妥善保存一个文件与utf-8日的名称,但这同一浏览器构成对日本将文件保存与utf-8chars未解释.所有其他浏览器进行测试似乎最好的工作/现(无论语言配置)的文件utf-8encoded不url编码。
  • 我找不到一个单一的浏览器实施Rfc5987/8187 在所有.我测试了最新的铬,火狐建立加即11和边缘。我试图设置的标题仅仅是文件*=utf-8"texturlencoded.pdf,设置这两filename=文本。pdf;文件*=utf-8"texturlencoded.pdf。没有一个特征Rfc5987/8187似乎得到正确处理的任何上述内容。

我们有一个类似的问题在一个网络应用程序,并最终通过阅读文件从HTML <input type="file">, ,并设置在网址的编码形式在一个新HTML <input type="hidden">.当然,我们必须除去的路径就像"C:\fakepath\",也就是返回的一些浏览器。

当然,这并不是直接答案行动的问题,但可能是一个解决办法用于其他人。

我通常URL-encode(与%xx)的文件,并且它似乎在所有的浏览器。你可能想要做一些测试。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top