我有以下代码,部署在https Asp站点上,使用MVC 4.0构建:
public FileResult ANotSoWorkingFunction(string filePath, string fileName)
{
pathToFile = string.Format("~/{0}/{1}", pathToFile, fileName);
return File(new FileStream(pathToFile, FileMode.Open), "application/pdf", fileName);
}
这对于Chrome,Firefox和IE9都有效(正如你们许多人可能已经猜到的那样)。但它会抛出一个:
---------------------------
Windows Internet Explorer
---------------------------
Internet Explorer cannot download someFileName from a_site.com.
Internet Explorer was not able to open this Internet site. The requested site is either unavailable or cannot be found. Please try again later.
---------------------------
OK
---------------------------
在IE6,7,8上
我非常感谢任何关于这个的想法或线索,因为我已经花了很多时间来玩html标题。
编辑:
以下是IE7的标题:
HTTP/1.1 200 OK
Cache-Control: private, no-cache="Set-Cookie"
Content-Type: application/pdf
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 4.0
X-AspNet-Version: 4.0.30319
Set-Cookie: .ASPXAUTH=; expires=Mon, 11-Oct-1999 21:00:00 GMT; path=/; HttpOnly
X-Powered-By: ASP.NET
Date: Wed, 04 Apr 2012 08:43:50 GMT
Content-Length: 233324
这是来自IE9的那些:
HTTP/1.1 200 OK
Cache-Control: private, no-cache="Set-Cookie"
Content-Type: application/pdf
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 4.0
X-AspNet-Version: 4.0.30319
Set-Cookie: .ASPXAUTH=; expires=Mon, 11-Oct-1999 21:00:00 GMT; path=/; HttpOnly
X-Powered-By: ASP.NET
Date: Wed, 04 Apr 2012 08:42:14 GMT
Content-Length: 233324
谢谢,
答案 0 :(得分:8)
我想我也遇到了你的问题。
我也在运行IIS 7.5并通过HTTPS请求上的操作下载PDF。由于我尚未分离的原因,IIS 7.5似乎将no-cache="Set-Cookie"
附加到我的Cache-Control
响应标头,无论我在响应上设置缓存设置。这导致the fairly well documented no-cache
issue on IE6, IE7, and IE8。
为了解决这个问题,我在FileContentResult周围做了一个小包装,它清除了标题,称为父标题,然后将Cacheability设置为' Private'。这方面支持IIS 7.5坚持在标题中添加no-cache="Set-Cookie"
,并在我测试的所有浏览器中正确下载文件。如果你想模仿我所做的,首先,这里是我的FileContentResult包装器。
public class PdfContentResult : FileContentResult {
public PdfContentResult(byte[] data) : base(data, "application/pdf") { }
public PdfContentResult(byte[] data, string fileName) : this(data) {
if (fileName == null) {
throw new ArgumentNullException("fileName");
}
this.FileDownloadName = fileName;
}
public override void ExecuteResult(ControllerContext context) {
context.HttpContext.Response.ClearHeaders();
base.ExecuteResult(context);
context.HttpContext.Response.Cache.SetCacheability(HttpCacheability.Private);
}
}
然后我向我的ControllerExtensions
添加了一个扩展方法,以便找到它:
public static class ControllerExtensions {
public static PdfContentResult Pdf(this Controller controller, byte[] fileContents, string fileName) {
return new PdfContentResult(fileContents, fileName);
}
}
最后,在Action中,我做了相同的事情:
public ActionResult MyGeneratedPdf() {
byte[] myPdfContentInByteStream = GetPdfFromModel();
return this.Pdf(myPdfContentInByteStream, "MyFile.pdf");
}
显然,如果您要下载各种数据类型,您可能不希望将解决方法与PDF紧密绑定。
答案 1 :(得分:1)
我们通过在流式传输文件之前更改缓存控制标头来解决此问题。
简化代码示例:
var browserInformation = Request.Browser;
//Set as private if current browser type is IE
Response.AppendHeader("cache-control",
browserInformation.Browser == "IE" ? "private" : "no-cache");
return File(fileName, contentType, downloadFileName);
这有效(yay)..但是我不知道为什么我们必须以这种方式为特定网站这样做。我们有四个网站在同一个盒子上运行,所有这些网站都在SSL下,只有一个网站有这个标题问题。我比较了web.config文件并查看了IIS中的设置,但无法进一步说明为什么一个站点需要明确设置这些头文件。
如果有人有更多要添加上面(添加的clairty)那将是伟大的。
答案 2 :(得分:0)
在旧版本的IE中,如果用户尝试通过HTTPS连接下载文件,则任何阻止缓存的响应标头都将导致文件下载过程失败。以下是引起问题的最常见标题:
您可以创建一个ActionFilterAttribute,它将为您清除缓存标头:
public class ClearCacheHeadersAttribute : FilterAttribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext filterContext)
{
return;
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext.Current.Response.Headers.Remove("Cache-Control");
HttpContext.Current.Response.Headers.Remove("Vary");
HttpContext.Current.Response.Headers.Remove("Pragma");
//Set the cache headers any way you like keeping in mind which values can brake the download
}
}
用它装饰你的动作:
[ClearCacheHeaders]
public FileResult ANotSoWorkingFunction(string filePath, string fileName)
{
pathToFile = string.Format("~/{0}/{1}", pathToFile, fileName);
return File(new FileStream(pathToFile, FileMode.Open), "application/pdf", fileName);
}