代码之家  ›  专栏  ›  技术社区  ›  wweicker

生成PDF,IE和HTTPS出错

  •  12
  • wweicker  · 技术社区  · 15 年前

    我正在用ASP.NET 2.0将PDF流式传输到浏览器。这适用于HTTP和所有浏览器上的所有浏览器 除了 通过HTTPS实现IE。据我所知,这在IE的所有版本中(在过去的5年左右)都有效,但我们的客户最近才开始报告问题。我怀疑 不将加密页保存到磁盘 安全选项在默认情况下被禁用,并且在某个时刻默认启用(Internet选项->高级->安全)。关闭此选项有助于解决问题,但不能作为长期解决方案。

    我收到的错误消息是:

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

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

    用于创建PDF的工具是ActiveReports from DataDynamics . 创建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不会代表我发送缓存,因此我尝试将缓存控制设置为:private或public或maxage=,但这些都不起作用。

    这里有一个转折点:当我运行fiddler检查响应头时,一切都正常。我收到的邮件头是:

    HTTP/1.1 200 OK
    缓存控制:最大年龄=1
    日期:2009年7月29日星期三17:57:58格林尼治标准时间
    内容类型:应用程序/pdf
    服务器:Microsoft IIS/6.0
    MicrosoftOfficeWeb服务器:5.0_pub
    x-powered-by:asp.net
    X-ASPNET-版本:2.0.50727
    内容处置:附件;文件名=statement.pdf
    内容编码:gzip
    变化:接受编码
    传输编码:分块

    我一关掉小提琴再试一次,它就又失败了。我注意到的另一件事是,当小提琴手跑的时候,我会得到一个 此网站的安全证书有问题 警告消息,我必须单击 继续访问此网站(不推荐) 通过。当fiddler关闭时,我不会遇到这个安全警告,它会立即失效。

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

    更新: 小提琴手的问题已经解决了,非常感谢EricLaw,所以现在它的行为始终如一(不管小提琴手是否在运行)。

    基于谷歌搜索,似乎有很多关于这个问题的报告遍布网络,每个报告都有自己特定的响应头组合,似乎可以解决每个案例的问题。我尝试过很多这样的建议,包括添加etag、lastmodified日期、删除vary头(使用fiddler)以及缓存控件和/或pragma头的几十种组合。我尝试了“内容传输编码:二进制”和“应用程序/强制下载”的ContentType。到目前为止没有任何帮助。有一个 few Microsoft KB articles ,所有这些都表明 缓存控制:无缓存 是罪魁祸首。还有其他想法吗?

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

    更新: 没有进展。我通过电子邮件将.saz文件从fiddler发送到ericlaw,他在调试IE时能够重现这个问题,但是还没有解决方案。赏金即将到期…

    12 回复  |  直到 10 年前
        1
  •  3
  •   EricLaw    15 年前

    你的 缓存控制 标题不正确。应该是 缓存控制:最大年龄=1 中间有破折号。试着先把它修好,看看是否有什么不同。

    通常,我会说最可能的罪魁祸首是您的vary头,因为这样的头通常会导致IE中的缓存出现问题: http://blogs.msdn.com/ieinternals/archive/2009/06/17/9769915.aspx . 您可能想尝试添加 埃塔格 到响应头。

    小提琴手不应该对可缓存性有任何影响(除非你已经写了规则),听起来就像你说的那样,这意味着可能存在某种时间问题。

    >不将加密页保存到磁盘安全选项,该选项在默认情况下被禁用

    这个选项 默认情况下仍然禁用(在IE6、7和8中),尽管IT管理员可以通过组策略打开它,一些主要公司也会这样做。

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

        2
  •  2
  •   wweicker    15 年前

    经过两个星期的疯狂追逐,我没有找到任何代码更改的组合,当 不将加密页保存到磁盘 '选项已打开。

    微软曾在数篇知识库文章和私人电子邮件中表示,这种行为是由设计造成的。当 不将加密页保存到磁盘 ‘选项是打开的,即行为正确,做它被要求做的。 This post 是迄今为止我找到的最好的资源,这可以解释为什么启用此设置以及启用它的优缺点:

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

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

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

    此时我们可以找到的最佳解决方案是与客户和用户交流使用此设置的替代方案:

    “关闭浏览器时使用“清空Internet临时文件文件夹”。每次浏览器关闭时,所有文件都将从缓存中清除,前提是没有来自其他浏览器实例或某个外部应用程序的文件锁定。

    在使用前需要考虑很多因素。 不将加密页保存到磁盘 '.听起来是一个很好的安全功能,但使用此功能的结果可能会导致帮助台呼叫因下载失败或性能下降而上升。”

        3
  •  2
  •   Rufel    14 年前

    我对想要传输的PDF文件也有类似的问题。即使有 Response.ClearHeaders() 我看到运行时添加了pragma和cache控制头。解决方案是清除IIS中的头(右键单击加载PDF的页面上的“属性”,然后单击“HTTP头”选项卡)。

        4
  •  1
  •   noctufaber    14 年前

    我发现这似乎对我有用:

    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
    
        5
  •  1
  •   Mr.Dark    14 年前

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

    ATT:Dark先生

        6
  •  1
  •   Arjan Tijms Mike Van    12 年前

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

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

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

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

    Response.ContentType = "application/pdf"
    

    您将使用

    Response.ContentType = "application/octet-stream"
    
        7
  •  0
  •   Dan Diplo    15 年前

    什么版本的IE?我记得微软发布了 a Hotfix for IE6 关于这个问题。希望这有用吗?

        8
  •  0
  •   Community CDub    8 年前

    我读过你的高速缓存控制系统,但我会分享 mine, that met my needs ,以防万一。

        9
  •  0
  •   Nir Levy    15 年前

    尝试禁用gzip压缩。

        10
  •  0
  •   DotNetUser    13 年前

    在这里添加它,希望有人能找到这个有用的,而不是浏览链接。

    这是我的密码

        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();
    
        11
  •  0
  •   metroas    10 年前

    就像操作一样,我花了好几天时间试图让它工作,但最后我还是做了,所以我想我会分享我的“组合”标题:

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

    希望能在某个地方救一个人一些痛苦!

        12
  •  0
  •   Matthew Jimenez    10 年前

    我遇到了一个类似的问题,试图通过SSL传输PDF,并将其放入iframe或对象中。我发现我的ASPX页面会一直重定向到不安全的URL版本,浏览器会阻止它。

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