ASP MVC 4'filename * = UTF-8'使用url param作为名称下载文件

时间:2013-09-24 08:17:42

标签: asp.net asp.net-mvc asp.net-mvc-4 utf-8 http-headers

我正在尝试在MVC中实现文件下载。这是当前的代码:

Response.Clear();
Response.Charset = "utf8";
Response.ContentType = string.IsNullOrEmpty(dokument.mimeType) ? MimeHelper.GetMimeFromBytes(dokument.Bin) : dokument.mimeType;
Response.AddHeader("Content-Disposition", "attachment; filename*=UTF-8''" + dokument.Nazwa.Replace(" ", "_").Replace(";", "%3B").Replace(",", "%2C"));
Response.BinaryWrite(dokument.Bin);
Response.Flush();
Response.End();

它工作得很好但是一些文件是以其数据库ID作为名称下载的。此值作为参数传递给Action。其他文件正确下载,我找不到它的原因。有谁知道可能有什么问题?

如果我删除'* = UTF-8''“逗号和分号代码未更改。

2 个答案:

答案 0 :(得分:1)

在某些情况下,很可能你的标题有问题。

生成正确的Content-Disposition标头比这复杂一点。最好从框架中已有的实现开始,只有在需要时才会选择 RFC 2231 ,如下所示:

public class ContentDispositionUtil
{
    public static string GetContentDisposition(string fileName)
    {
        try
        {
            return (new ContentDisposition() { FileName = fileName }).ToString();
        }
        catch (FormatException)
        {
            return GetRfc2231ContentDisposition(fileName);
        }
    }
 }

GetRfc2231ContentDisposition的实施是棘手的部分。通常,如果文件名中的每个字符对标题有效,并且如果没有正确编码,则需要检查它们。检查可以通过以下方法完成:

private static bool IsValidRfc2231ContentDispositionCharacter(byte character)
{
    if ((byte)'0' <= character && character <= (byte)'9')
        return true;
    if ((byte)'a' <= character && character <= (byte)'z')
        return true;
    if ((byte)'A' <= character && character <= (byte)'Z')
        return true;

    switch (character)
    {
        case (byte)'-':
        case (byte)'.':
        case (byte)'_':
        case (byte)'~':
        case (byte)':':
        case (byte)'!':
        case (byte)'$':
        case (byte)'&':
        case (byte)'+':
            return true;
    }

    return false;
}

简单的实现,但它显示了允许的字符。现在你可以进行这样的编码:

private const string _hexDigits = "0123456789ABCDEF";

private static string EncodeInvalidRfc2231ContentDispositionCharacter(int character)
{
    return "%" + _hexDigits[character >> 4] + _hexDigits[character % 16];
}

现在我们已准备好生成标题:

private static string GetRfc2231ContentDisposition(string filename)
{
    StringBuilder contentDispositionBuilder = new StringBuilder("attachment; filename*=UTF-8''");

    byte[] filenameBytes = Encoding.UTF8.GetBytes(filename);
    foreach (byte character in filenameBytes)
    {
        if (IsValidRfc2231ContentDispositionCharacter(character))
            contentDispositionBuilder.Append((char)character);
        else
        {
            contentDispositionBuilder.Append(EncodeInvalidRfc2231ContentDispositionCharacter((int)character));
        }
    }

    return contentDispositionBuilder.ToString();
}

现在你应该总是得到合适的标题。

P.S。当然,只有在需要的时候才能做到这一切,并尽可能使用FileResult提供的内置行动结果;)

答案 1 :(得分:0)

实际上我已经将标题生成更改为return File()并且它工作正常,尽管tpeczek提供的算法也可以。