How to encode the filename parameter of Content-Disposition header in HTTP?

前端 未结 18 1779
北荒
北荒 2020-11-21 06:15

Web applications that want to force a resource to be downloaded rather than directly rendered in a Web browser issue a Content-Disposition hea

相关标签:
18条回答
  • 2020-11-21 07:11

    RFC 6266 describes the “Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)”. Quoting from that:

    6. Internationalization Considerations

    The “filename*” parameter (Section 4.3), using the encoding defined in [RFC5987], allows the server to transmit characters outside the ISO-8859-1 character set, and also to optionally specify the language in use.

    And in their examples section:

    This example is the same as the one above, but adding the "filename" parameter for compatibility with user agents not implementing RFC 5987:

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

    Note: Those user agents that do not support the RFC 5987 encoding ignore “filename*” when it occurs after “filename”.

    In Appendix D there is also a long list of suggestions to increase interoperability. It also points at a site which compares implementations. Current all-pass tests suitable for common file names include:

    • attwithisofnplain: plain ISO-8859-1 file name with double quotes and without encoding. This requires a file name which is all ISO-8859-1 and does not contain percent signs, at least not in front of hex digits.
    • attfnboth: two parameters in the order described above. Should work for most file names on most browsers, although IE8 will use the “filename” parameter.

    That RFC 5987 in turn references RFC 2231, which describes the actual format. 2231 is primarily for mail, and 5987 tells us what parts may be used for HTTP headers as well. Don't confuse this with MIME headers used inside a multipart/form-data HTTP body, which is governed by RFC 2388 (section 4.4 in particular) and the HTML 5 draft.

    0 讨论(0)
  • 2020-11-21 07:11

    If you are using a nodejs backend you can use the following code I found here

    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);
    }
    
    0 讨论(0)
  • 2020-11-21 07:12

    In ASP.NET Web API, I url encode the 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

    0 讨论(0)
  • 2020-11-21 07:14
    • There is no interoperable way to encode non-ASCII names in Content-Disposition. Browser compatibility is a mess.

    • The theoretically correct syntax for use of UTF-8 in Content-Disposition is very weird: filename*=UTF-8''foo%c3%a4 (yes, that's an asterisk, and no quotes except an empty single quote in the middle)

    • This header is kinda-not-quite-standard (HTTP/1.1 spec acknowledges its existence, but doesn't require clients to support it).

    There is a simple and very robust alternative: use a URL that contains the filename you want.

    When the name after the last slash is the one you want, you don't need any extra headers!

    This trick works:

    /real_script.php/fake_filename.doc
    

    And if your server supports URL rewriting (e.g. mod_rewrite in Apache) then you can fully hide the script part.

    Characters in URLs should be in UTF-8, urlencoded byte-by-byte:

    /mot%C3%B6rhead   # motörhead
    
    0 讨论(0)
  • 2020-11-21 07:16

    We had a similar problem in a web application, and ended up by reading the filename from the HTML <input type="file">, and setting that in the url-encoded form in a new HTML <input type="hidden">. Of course we had to remove the path like "C:\fakepath\" that is returned by some browsers.

    Of course this does not directly answer OPs question, but may be a solution for others.

    0 讨论(0)
  • 2020-11-21 07:18

    I normally URL-encode (with %xx) the filenames, and it seems to work in all browsers. You might want to do some tests anyway.

    0 讨论(0)
提交回复
热议问题