【问题标题】:How to avoid duplicate content-disposition headers with MVC3 FileContentResult?如何使用 MVC3 FileContentResult 避免重复的内容处置标头?
【发布时间】:2012-01-26 20:25:32
【问题描述】:

我们有一些文件存储在 sql 数据库中。在 ASP.NET MVC3 表单上,我们显示 2 个链接:

查看此文件 |下载这个文件

这些链接指向这些相应的操作方法。下载按预期进行——单击链接会强制在浏览器中出现保存对话框。但是,显示会导致向浏览器发送重复的 Content-Disposition 标头,从而导致 Chrome 出现错误,并导致 Firefox 出现空白页面。

[ActionName("display-file")]
public virtual ActionResult DisplayFile (Guid fileId, string fileName)
{
    var file = _repos.GetFileInfo(fileId);
    if (file != null)
    {
        Response.AddHeader("Content-Disposition", 
            string.Format("inline; filename={0}", file.Name));
        return File(file.Content, file.MimeType, file.Name);
    }
}

[ActionName("download-file")]
public virtual ActionResult DownloadFile (Guid fileId, string fileName)
{
    var file = _repos.GetFileInfo(fileId);
    if (file != null)
    {
        return File(file.Content, file.MimeType, file.Name);
    }
}

以下是发送到浏览器以进行显示操作的 2 个标头:

Content-Disposition: inline; filename=name-of-my-file.pdf
Content-Disposition: attachment; filename="name-of-my-file.pdf"

我尝试更改我的自定义内容处置标头以将文件名包含在双引号中,但它仍然向浏览器发送了 2 个标头。我还尝试在添加自定义标头之前删除 Content-Disposition 标头,但似乎在返回 FileContentResult 后正在添加附件标头。

这段代码曾经有效。我昨天进行了一次测试,发现它不再在 Chrome 或 Firefox 中工作。这可能是由于浏览器中的更新所致。 IE8 和 Safari 仍然可以正确打开文件。

更新

再次感谢达林,你是对的。由于another question you answered,我们实际上使用了这种方法。

关于我们最终如何解决这个问题的更多信息,我们有一个显示文件链接的自定义路由:

context.MapRoute(null,
    "path/to/display-file-attachment/{fileId}/{fileName}",
    new
    {
        area = "AreaName",
        controller = "ControllerName",
        action = "DisplayFile",
    }
);

页面上的超链接通过route参数将文件名传递给action方法,所以它已经是URL的一部分了。因此,当用户决定下载文件时(通过单击浏览器 PDF 查看器中的保存图标),我们不需要添加自定义内容处置标题以使文件名与系统匹配。所以我们只使用了这个:

[ActionName("display-file")]
public virtual ActionResult DisplayFile (Guid fileId, string fileName)
{
    var file = _repos.GetFileInfo(fileId);
    if (file != null)
    {
        // no custom content-disposition header, and no 3rd fileName argument
        return File(file.Content, file.MimeType);
    }
}

【问题讨论】:

  • Firefox 和 Chrome 在处理 Content-Disposition 标头方面确实变得更加严格。
  • @JulianReschke,您能否详细说明非 ASCII 字符?我们尚未使用文件名中的 unicode 字符对此进行测试。
  • 为了让 C-D 文件名中的非 ASCII 在所有浏览器中“工作”,服务器当前需要进行用户代理嗅探。请参阅 greenbytes.de/tech/tc2231greenbytes.de/tech/webdav/rfc6266.html。我怀疑 ASP.net 是否正确,但我很想知道其他情况。

标签: asp.net-mvc-3 download content-disposition


【解决方案1】:

当您使用重载File(byte[] contents, string mimeType, string fileName) 时,Content-Disposition 标头会自动添加到带有attachment 的响应中,因此您无需再次添加它。对于inline,您可以使用以下重载File(byte[] contents, string mimeType) 并手动添加Content-Disposition 标头:

[ActionName("display-file")]
public virtual ActionResult DisplayFile(Guid fileId)
{
    var file = _repos.GetFileInfo(fileId);
    var cd = new ContentDisposition
    {
        Inline = true,
        FileName = file.Name
    };
    Response.AddHeader("Content-Disposition", cd.ToString()); 
    return File(file.Content, file.MimeType);
}

[ActionName("download-file")]
public virtual ActionResult DownloadFile(Guid fileId)
{
    var file = _repos.GetFileInfo(fileId);
    return File(file.Content, file.MimeType, file.Name);
}

【讨论】:

  • 你打败了我,我正要发布一个类似的答案。省略第三个 fileName 参数有效。但是,在我们的例子中不需要添加内容配置。只需 return File(file.Content, file.MimeType); 即可,因为文件名来自自定义路由。
  • 好吧,希望框架对非 ASCII 字符做正确的事情...
  • @JulianReschke,什么非 ASCII 字符?该框架对它们没有任何作用。由你决定。如果您在谈论文件名中的非 ASCII 字符,那么是的,那是可怕的 PITA。但这不是您希望框架对您有所帮助的事情。这只是不同浏览器实现不同的东西。简而言之,这是不应该使用的东西:-)
  • 达林:嗯,它在除 Safari 之外的所有当前浏览器中都可以正常工作。
  • 唯一的缺点是我的一些检查文件名的单元测试失败了。找不到让我的单元测试检查标头的方法,并且 FileDownloadName 属性为空。
猜你喜欢
  • 2020-08-17
  • 1970-01-01
  • 2014-12-02
  • 1970-01-01
  • 1970-01-01
  • 2012-04-30
  • 2012-12-15
  • 2010-10-30
  • 2016-05-05
相关资源
最近更新 更多