0

我正在尝试在 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''" 逗号和分号代码不会更改。

4

2 回答 2

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

现在你应该总是得到正确的标题。

PS 当然,只有在真正需要时才执行所有这些操作,并FileResult尽可能使用内置的操作结果;)

于 2013-09-24T11:39:23.490 回答
0

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

于 2013-09-25T12:57:39.500 回答