12

我在 ASP.NET 2.0 中将 PDF 流式传输到浏览器。这适用于所有通过 HTTP 的浏览器和所有浏览器,除了通过 HTTPS 的 IE。据我所知,这曾经在所有版本的 IE 中都有效(过去 5 年左右),但我们的客户最近才开始报告问题。我怀疑不要将加密的页面保存到磁盘安全选项过去是默认禁用的,并且在某些时候默认启用(Internet 选项 -> 高级 -> 安全)。作为一种变通方法,关闭此选项会有所帮助,但作为长期解决方案不可行。

我收到的错误消息是:

Internet Explorer 无法从 www.sitename.com 下载 OutputReport.aspx。

Internet Explorer 无法打开此 Internet 站点。请求的站点不可用或找不到。请稍后再试。

用于创建 PDF 的工具是来自DataDynamics的 ActiveReports 。创建 PDF 后,下面是发送它的代码:

Response.ClearContent()
Response.ClearHeaders()
Response.AddHeader("cache-control", "max-age=1")
Response.ContentType = "application/pdf"
Response.AddHeader("content-disposition", "attachment; filename=statement.pdf")
Response.AddHeader("content-length", mem_stream.Length.ToString)
Response.BinaryWrite(mem_stream.ToArray())
Response.Flush()
Response.End()  

注意:如果我没有明确指定缓存控制,那么 .NET 会代表我发送无缓存,所以我尝试将缓存控制设置为:私有或公共或 maxage=#,但这些似乎都不起作用。

这是一个转折点:当我运行 Fiddler 来检查响应头时,一切正常。我收到的标题是:

HTTP/1.1 200 OK
缓存控制:max-age=1
日期:2009 年 7 月 29 日星期三 17:57:58 GMT
内容类型:应用程序/pdf
服务器:Microsoft-IIS/6.0
MicrosoftOfficeWebServer:5.0_Pub
X-Powered-By :ASP.NET
X-AspNet-Version:2.0.50727
内容配置:附件;文件名=statement.pdf
内容编码:gzip
变化:接受编码
传输编码:分块

一旦我关闭 Fiddler 并重试,它就会再次失败。我注意到的另一件事是,当 Fiddler 运行时,我收到“此网站的安全证书存在问题”警告消息,我必须单击“继续访问该网站(不推荐) ”才能通过。当 Fiddler 关闭时,我不会遇到此安全警告,它会立即失败。

我很好奇 Fiddler 和浏览器之间发生了什么,因此它在 Fiddler 运行时工作,但在不运行时中断,但更重要的是,有没有人知道如何更改我的代码,以便将 PDF 流式传输到 IE 无需进行更改即可工作到客户端机器?

更新: Fiddler 问题已解决,非常感谢 EricLaw,所以现在它的行为一致(损坏,无论 Fiddler 是否运行)。

根据 Google 搜索,整个网络上似乎有很多关于同一问题的报告,每个报告都有自己特定的响应标头组合,似乎可以针对各自的情况解决问题。我已经尝试了许多这些建议,包括添加 ETag、LastModified 日期、删除 Vary 标头(使用 Fiddler)以及 Cache-Control 和/或 Pragma 标头的数十种组合。我尝试了 ContentType 的“Content-Transfer-Encoding: binary”以及“application/force-download”。到目前为止没有任何帮助。有一些 Microsoft 知识库 文章,所有这些都表明Cache-Control: no-cache是罪魁祸首。还有其他想法吗?

更新:顺便说一下,为了完整起见,Excel 和 Word 输出也会出现同样的问题。

更新:没有取得任何进展。我将 .SAZ 文件从 Fiddler 通过电子邮件发送给 EricLaw,他能够在调试 IE 时重现该问题,但还没有解决方案。赏金即将到期...

4

12 回答 12

3

您的Cache-Control标头不正确。它应该是Cache-Control: max-age=1,中间有破折号。尝试先修复它,看看它是否有所作为。

通常,我会说最可能的罪魁祸首是您的 Vary 标头,因为此类标头通常会导致 IE 中的缓存问题:http: //blogs.msdn.com/ieinternals/archive/2009/06/17/9769915.aspx。您可能想尝试将ETAG添加到响应标头中。

Fiddler 应该对可缓存性没有影响(除非您已经编写了规则),而且听起来您是在说它确实如此,这表明可能存在某种时间问题。

>不将加密页面保存到磁盘安全选项过去默认是禁用的

此选项在默认情况仍处于禁用状态(在 IE6、7 和 8 中),尽管 IT 管理员可以通过组策略将其打开,一些大公司也这样做。

顺便说一句,您在运行 Fiddler 时看到证书错误的原因是您没有选择信任 Fiddler 根证书;有关此主题的更多信息,请参阅http://www.fiddler2.com/fiddler/help/httpsdecryption.asp

于 2009-07-30T18:49:22.757 回答
2

经过两周的疯狂追逐,当“不将加密的页面保存到磁盘”选项打开时,我无法找到任何代码更改组合来允许这种流式传输 PDF、Excel 或 Word 文档的方法。

微软在许多知识库文章和私人电子邮件中表示,这种行为是设计使然。看来,当“不要将加密的页面保存到磁盘”选项打开时,IE 的行为正确并按照指示执行。 这篇文章是迄今为止我找到的最好的资源,它解释了为什么要启用此设置以及启用它的利弊:

“在处理 SSL (HTTPS) 连接时,‘不要将加密的页面保存到磁盘’会发挥作用。就像 Web 服务器可以发送有关如何缓存文件的已完成信息一样,基本上可以将 Internet Explorer 设置为不将文件保存到SSL (HTTPS) 连接期间的缓存,无论 Web 服务器是否建议您都可以。

打开此功能的好处是什么,安全性是打开此功能的首要原因。页面不存储在 Internet 临时文件缓存中。

缺点是什么?性能缓慢,因为即使在页面上使用了十几次的 1 字节 gif 图像也必须每次都从网络服务器获取,所以没有任何内容保存到缓存中。更糟糕的是,某些用户操作可能会失败,例如下载的文件将被删除,出现错误或打开 PDF 文档将无法列举一些场景。”

目前我们能找到的最佳解决方案是与我们的客户和用户沟通,了解使用此设置的替代方案:

“在浏览器关闭时使用‘Empty Temporary Internet Files folder’。每次浏览器关闭时,所有文件都将从缓存中清除,假设没有来自浏览器的另一个实例或某些外部应用程序的文件锁定。

在使用“不要将加密的页面保存到磁盘”之前需要考虑很多。听起来像是一项很棒的安全功能,但使用此功能的结果可能会导致您的帮助台呼叫因下载失败或性能下降而增加。”

于 2009-08-11T18:28:37.497 回答
2

我发现这似乎对我有用:

Dim browser As System.Web.HttpBrowserCapabilities = Request.Browser
If (browser.Browser = "IE") Then
  Response.AppendHeader("cache-control", "private") ' ie only
Else
  Response.AppendHeader("cache-control", "no-cache") ' all others (FF/Chrome tested)
End If
于 2010-07-15T23:36:00.847 回答
2

我想流式传输的 PDF 文件也有类似的问题。即使Response.ClearHeaders()我看到在运行时添加了 Pragma 和 Cache-Control 标头。解决方案是清除 IIS 中的标头(右键单击 -> 加载 PDF 的页面上的属性,然后单击“Http 标头”选项卡)。

于 2011-01-17T15:51:57.223 回答
1

我们很久以前就面临过类似的问题——我们所做的是我们(这是 Java EE)。在 Web 应用程序配置中,我们添加

<mime-mapping>
    <extension>PDF</extension>
    <mime-type>application/octet-stream</mime-type>
</mime-mapping>

这将使来自您的 Web 应用程序的任何 pdf 文件被下载,而不是浏览器尝试呈现。

编辑:看起来你正在流式传输它。在这种情况下,您将在代码中而不是在配置中使用 mime 类型作为 application/octet-stream。所以这里而不是

Response.ContentType = "application/pdf"

你会用

Response.ContentType = "application/octet-stream"
于 2009-08-11T05:13:57.133 回答
1

已解决:这是一个 IE 问题,不是来自应用程序...用这个修复它:http: //support.microsoft.com/kb/323308 它对我来说非常适合,经过很长时间的尝试。

ATT:黑暗先生

于 2011-05-18T16:22:22.867 回答
0

什么版本的IE?我记得微软针对这个问题发布了 IE6 的修补程序。希望有什么用?

于 2009-07-29T19:00:39.433 回答
0

我读过你的缓存控制鹅追逐,但我会分享我的,满足我的需求,以防它有帮助。

于 2009-08-10T19:47:03.007 回答
0

尝试禁用 gzip 压缩。

于 2009-08-11T11:31:58.020 回答
0

在此处添加它,希望有人可能会发现这很有用,而不是通过链接。

这是我的代码

    byte[] bytes = // get byte array from DB

    Response.Clear();
    Response.ClearContent();
    Response.ClearHeaders();
    Response.Buffer = true;

    // Prevent this page from being cached.
    //  NOTE: we cannot use the CacheControl property, or set the PRAGMA header value due to a flaw re: PDF/SSL/IE
    Response.Expires = -1; 

    Response.ContentType = "application/pdf";
    // Specify the number of bytes to be sent
    Response.AppendHeader("content-length", bytes.Length.ToString());

    Response.BinaryWrite(bytes);    

            // Wrap Up
    Response.Flush();
    Response.Close();
    Response.End();
于 2012-02-08T00:12:16.937 回答
0

就像 OP 一样,我几天来一直在摸不着头脑,试图让它发挥作用,但我最终做到了,所以我想我会分享我的标题“组合”:

            if (System.Web.HttpContext.Current.Request.Browser.Browser == "InternetExplorer"
                && System.Web.HttpContext.Current.Request.Browser.Version == "8.0")
            {
                System.Web.HttpContext.Current.Response.Clear();
                System.Web.HttpContext.Current.Response.ClearContent();
                System.Web.HttpContext.Current.Response.ClearHeaders();
                System.Web.HttpContext.Current.Response.ContentType = "application/octet-stream";

                System.Web.HttpContext.Current.Response.AppendHeader("Pragma", "public");
                System.Web.HttpContext.Current.Response.AppendHeader("Cache-Control", "private, max-age=60");
                System.Web.HttpContext.Current.Response.AppendHeader("Content-Transfer-Encoding", "binary");

                System.Web.HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=" + document.Filename);
                System.Web.HttpContext.Current.Response.AddHeader("content-length", document.Data.LongLength.ToString());

                System.Web.HttpContext.Current.Response.BinaryWrite(document.Data);
            }

希望可以在某个地方为某人节省一些痛苦!

于 2015-03-06T09:33:23.603 回答
0

我在尝试通过 SSL 流式传输 PDF 并将其放入 iframe 或对象时遇到了类似的问题。我发现我的 aspx 页面会不断重定向到 URL 的非安全版本,并且浏览器会阻止它。

我发现从 ASPX 页面切换到 ASHX 处理程序解决了我的重定向问题。

于 2015-04-17T17:23:09.253 回答