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

前端 未结 18 2170
北荒
北荒 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:10

    I know this is an old post but it is still very relevant. I have found that modern browsers support rfc5987, which allows utf-8 encoding, percentage encoded (url-encoded). Then Naïve file.txt becomes:

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

    Safari (5) does not support this. Instead you should use the Safari standard of writing the file name directly in your utf-8 encoded header:

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

    IE8 and older don't support it either and you need to use the IE standard of utf-8 encoding, percentage encoded:

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

    In ASP.Net I use the following code:

    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);
    

    I tested the above using IE7, IE8, IE9, Chrome 13, Opera 11, FF5, Safari 5.

    Update November 2013:

    Here is the code I currently use. I still have to support IE8, so I cannot get rid of the first part. It turns out that browsers on Android use the built in Android download manager and it cannot reliably parse file names in the standard way.

    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);
    

    The above now tested in IE7-11, Chrome 32, Opera 12, FF25, Safari 6, using this filename for download: 你好abcABCæøåÆØÅäöüïëêîâéíáóúýñ½§!#¤%&()=`@£$€{[]}+´¨^~'-_,;.txt

    On IE7 it works for some characters but not all. But who cares about IE7 nowadays?

    This is the function I use to generate safe file names for Android. Note that I don't know which characters are supported on Android but that I have tested that these work for sure:

    private static readonly Dictionary 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);
    }
    

    @TomZ: I tested in IE7 and IE8 and it turned out that I did not need to escape apostrophe ('). Do you have an example where it fails?

    @Dave Van den Eynde: Combining the two file names on one line as according to RFC6266 works except for Android and IE7+8 and I have updated the code to reflect this. Thank you for the suggestion.

    @Thilo: No idea about GoodReader or any other non-browser. You might have some luck using the Android approach.

    @Alex Zhukovskiy: I don't know why but as discussed on Connect it doesn't seem to work terribly well.

提交回复
热议问题