Asp.net

生成 PDF,IE 和 HTTPS 出錯

  • April 17, 2015

我在 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 時重現該問題,但還沒有解決方案。賞金即將到期…

經過兩週的瘋狂追逐,當“不將加密的頁面保存到磁碟”選項打開時,我無法找到任何程式碼更改組合來允許這種流式傳輸 PDF、Excel 或 Word 文件的方法。

微軟在許多知識庫文章和私人電子郵件中表示,這種行為是設計使然。看來,當“不要將加密的頁面保存到磁碟”選項打開時,IE 的行為正確並按照指示執行。 這篇文章是迄今為止我找到的最好的資源,它解釋了為什麼要啟用此設置以及啟用它的利弊:

> > > > > > “在處理 SSL (HTTPS) 連接時,‘不要將加密的頁面保存到磁碟’會發揮作用。就像 Web 伺服器可以發送有關如何記憶體文件的已完成資訊一樣,基本上可以將 Internet Explorer 設置為不將文件保存到SSL (HTTPS) 連接期間的記憶體,無論 Web 伺服器是否建議您都可以。 > > > > > > 打開此功能的好處是什麼,安全性是打開此功能的首要原因。頁面不儲存在 Internet 臨時文件記憶體中。 > > > > > > 缺點是什麼?性能緩慢,因為即使在頁面上使用了十幾次的 1 字節 gif 圖像也必須每次都從網路伺服器獲取,所以沒有任何內容保存到記憶體中。更糟糕的是,某些使用者操作可能會失敗,例如下載的文件將被刪除,出現錯誤或打開 PDF 文件將無法列舉一些場景。” > > > > > > > > >

目前我們能找到的最佳解決方案是與我們的客戶和使用者溝通,了解使用此設置的替代方案:

> > > > > > “使用‘當瀏覽器關閉時清空 Internet 臨時文件文件夾’。每次瀏覽器關閉時,所有文件都將從記憶體中清除,假設沒有來自瀏覽器的另一個實例或某些外部應用程序的文件鎖定。 > > > > > > 在使用“不要將加密的頁面保存到磁碟”之前需要考慮很多。聽起來像是一項很棒的安全功能,但使用此功能的結果可能會導致您的幫助台呼叫因下載失敗或性能下降而增加。” > > > > > > > > >

您的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

引用自:https://stackoverflow.com/questions/1202285