IE7/8:PDF 文件无法使用 HTTP GET 下载

发布于 2025-01-03 15:00:52 字数 5226 浏览 0 评论 0原文

我正在使用 DataGridView 来显示语句列表。其中一栏是 LinkBut​​ton,它允许您下载 PDF 格式的特定声明。我的代码在所有浏览器中都能完美运行,除了 IE7 和 IE7 之外。 IE8。我不知道为什么会这样。

       <asp:GridView ID="dgvEStatements" runat="server" EnableSortingAndPagingCallbacks="False"
            EnableViewState="true" GridLines="Vertical" Width="100%" AutoGenerateColumns="False"
            CssClass="gridheader" EmptyDataText="<%$ Resources:IBEStatements, dgvEStatements_NoRows %>"
            OnPageIndexChanging="dgvEStatements_PageIndexChanging" OnRowCommand="dgvEStatements_RowCommand"
            OnRowDataBound="dgvEStatements_RowDataBound">
            <Columns>
                <asp:BoundField DataField="Date" HeaderText="<%$ Resources:IBEStatements, dgvEStatements_DateHeader %>"
                    HeaderStyle-CssClass="lhs">
                    <ItemStyle CssClass="lhs" />
                </asp:BoundField>
                <asp:BoundField DataField="Description" HeaderText="<%$ Resources:IBEStatements, dgvEStatements_DescriptionHeader %>"
                    HeaderStyle-CssClass="lhs" />
                <asp:BoundField DataField="DocumentType" Visible="false" HeaderText="<%$ Resources:IBEStatements, dgvEStatements_DocumentTypeHeader %>"
                    HeaderStyle-CssClass="lhs">
                    <ItemStyle CssClass="lhs" />
                </asp:BoundField>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:LinkButton ID="lnkDownloadEStatement" runat="server" Text="<%$ Resources:IBEStatements, lnkDownloadEStatement %>" />
                    </ItemTemplate>
                    <ItemStyle CssClass="rhs" />
                </asp:TemplateField>
            </Columns>

        </asp:GridView>

网格的 RowDataBound 事件执行以下操作:

protected void dgvEStatements_RowDataBound(object sender, GridViewRowEventArgs e)
{

    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        LinkButton lnkEStatement = (LinkButton)e.Row.FindControl("lnkDownloadEStatement");

        string fileId = DataBinder.Eval(e.Row.DataItem, "StatementID").ToString();
        lnkEStatement.Attributes.Add("onclick", "javascript:EStatementDownload('" + fileId + "'); return false;");
    }        
}

调用创建 PDF 的页面的 Javascript 函数:

function EStatementDownload(fileid) {
    var iframe = document.createElement("iframe");
    iframe.src = "EStatementFile.ashx?fileid=" + fileid;
    iframe.style.display = "none";
    document.body.appendChild(iframe);
}

最后,EStatementFile.ashx 的代码如下所示:

    public void ProcessRequest(HttpContext context)
    {
        try
        {
            string args = context.Request.QueryString["fileid"].ToString();

            int statementID = 0;
            int.TryParse(args, out statementID);

            string documentID = String.Empty;
            string accountnumber = String.Empty;
            DateTime fileDate = DateTime.MinValue;

            foreach (EStatement item in EStatementListing.EStatements)
            {
                if (statementID == item.StatementID)
                {
                    documentID = item.DocumentID;
                    accountnumber = item.AccountNumber;
                    fileDate = item.DocumentDate;
                    break;
                }
            }

            EStatementFacade estatementFacade = new EStatementFacade();
            EStatement estatement = estatementFacade.GetEStatement(documentID, accountnumber, fileDate);
            if (estatement.Document != null)
            {
                context.Response.Clear();
                context.Response.ContentType = "Application/pdf";
                context.Response.Cache.SetCacheability(HttpCacheability.Private);
                context.Response.AppendHeader("Cache-Control", "private; must-revalidate");
                context.Response.AppendHeader("Pragma", "private");
                context.Response.AddHeader("content-disposition", "attachment; filename=" + fileDate.ToString("ddMMyyyy") + ".pdf");
                context.Response.BinaryWrite(estatement.Document);
                context.Response.Flush();                                      
            }
        }
        catch (Exception ex)
        {
        }
        finally
        {
            context.ApplicationInstance.CompleteRequest();
        }
    }

单击网格上的 Linkbutton 时,以下 javascript 信息将显示在Firebug,这可能对查找问题有用: Firebug Output

一些有趣的事情需要注意,如果我在 context.Response.Flush() 之后直接调用 context.Response.End() ,我得到以下异常。现在,无论异常如何,文件下载对话框仍然会在所有浏览器中显示,但在 IE7 和 IE7 中仍然显示。 IE8,仍然没有下载对话框。

context.Response.End(); “context.Response.End()”引发了“System.Threading.ThreadAbortException”类型的异常 base {System.SystemException}:{无法计算表达式,因为代码已优化或本机框架位于调用堆栈的顶部。} ExceptionState:无法计算表达式,因为代码已优化或本机框架位于调用堆栈顶部。

可能与 iFrame 有关?

在此处输入图像描述

PS:保存最后一张图片以查看大图

I'm using a DataGridView to display a list of statements. One of the columns is a LinkButton, which allows you to download that specific statement in PDF format. My code works perfectly in ALL BROWSERS, except for IE7 & IE8. I have no idea why that is.

       <asp:GridView ID="dgvEStatements" runat="server" EnableSortingAndPagingCallbacks="False"
            EnableViewState="true" GridLines="Vertical" Width="100%" AutoGenerateColumns="False"
            CssClass="gridheader" EmptyDataText="<%$ Resources:IBEStatements, dgvEStatements_NoRows %>"
            OnPageIndexChanging="dgvEStatements_PageIndexChanging" OnRowCommand="dgvEStatements_RowCommand"
            OnRowDataBound="dgvEStatements_RowDataBound">
            <Columns>
                <asp:BoundField DataField="Date" HeaderText="<%$ Resources:IBEStatements, dgvEStatements_DateHeader %>"
                    HeaderStyle-CssClass="lhs">
                    <ItemStyle CssClass="lhs" />
                </asp:BoundField>
                <asp:BoundField DataField="Description" HeaderText="<%$ Resources:IBEStatements, dgvEStatements_DescriptionHeader %>"
                    HeaderStyle-CssClass="lhs" />
                <asp:BoundField DataField="DocumentType" Visible="false" HeaderText="<%$ Resources:IBEStatements, dgvEStatements_DocumentTypeHeader %>"
                    HeaderStyle-CssClass="lhs">
                    <ItemStyle CssClass="lhs" />
                </asp:BoundField>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:LinkButton ID="lnkDownloadEStatement" runat="server" Text="<%$ Resources:IBEStatements, lnkDownloadEStatement %>" />
                    </ItemTemplate>
                    <ItemStyle CssClass="rhs" />
                </asp:TemplateField>
            </Columns>

        </asp:GridView>

The RowDataBound event for the Grid does the following:

protected void dgvEStatements_RowDataBound(object sender, GridViewRowEventArgs e)
{

    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        LinkButton lnkEStatement = (LinkButton)e.Row.FindControl("lnkDownloadEStatement");

        string fileId = DataBinder.Eval(e.Row.DataItem, "StatementID").ToString();
        lnkEStatement.Attributes.Add("onclick", "javascript:EStatementDownload('" + fileId + "'); return false;");
    }        
}

Javascript function to call the page that creates the PDF:

function EStatementDownload(fileid) {
    var iframe = document.createElement("iframe");
    iframe.src = "EStatementFile.ashx?fileid=" + fileid;
    iframe.style.display = "none";
    document.body.appendChild(iframe);
}

Finally, the code behind for EStatementFile.ashx looks like this:

    public void ProcessRequest(HttpContext context)
    {
        try
        {
            string args = context.Request.QueryString["fileid"].ToString();

            int statementID = 0;
            int.TryParse(args, out statementID);

            string documentID = String.Empty;
            string accountnumber = String.Empty;
            DateTime fileDate = DateTime.MinValue;

            foreach (EStatement item in EStatementListing.EStatements)
            {
                if (statementID == item.StatementID)
                {
                    documentID = item.DocumentID;
                    accountnumber = item.AccountNumber;
                    fileDate = item.DocumentDate;
                    break;
                }
            }

            EStatementFacade estatementFacade = new EStatementFacade();
            EStatement estatement = estatementFacade.GetEStatement(documentID, accountnumber, fileDate);
            if (estatement.Document != null)
            {
                context.Response.Clear();
                context.Response.ContentType = "Application/pdf";
                context.Response.Cache.SetCacheability(HttpCacheability.Private);
                context.Response.AppendHeader("Cache-Control", "private; must-revalidate");
                context.Response.AppendHeader("Pragma", "private");
                context.Response.AddHeader("content-disposition", "attachment; filename=" + fileDate.ToString("ddMMyyyy") + ".pdf");
                context.Response.BinaryWrite(estatement.Document);
                context.Response.Flush();                                      
            }
        }
        catch (Exception ex)
        {
        }
        finally
        {
            context.ApplicationInstance.CompleteRequest();
        }
    }

When the Linkbutton on the grid is clicked, the following javascript information is displayed in Firebug, which might be useful in finding the issue:
Firebug Output

Something interesting to note, if I call context.Response.End() directly after context.Response.Flush(), I get the following exception. Now the file download dialog is still being displayed in all browsers regardless of the exception, but in IE7 & IE8, still no download dialog.

context.Response.End();
'context.Response.End()' threw an exception of type 'System.Threading.ThreadAbortException'
base {System.SystemException}: {Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.}
ExceptionState: Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.

It might have something to do with the iFrame?

enter image description here

PS: Save the last image to see large image

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

帥小哥 2025-01-10 15:00:52

你能试试这个吗——

    Response.Buffer = true;
            Response.Clear();
            Response.ClearContent();
            Response.ClearHeaders();
            Response.ContentType = "application/pdf";
            Response.AddHeader(
              "Content-Disposition",
              string.Format("attachment; filename={0}",filename)
            );
            // stream pdf bytes to the browser
            Response.OutputStream.Write(estatement.Document, 0, estatement.Document.Length);
            Response.End();

Can you try this-

    Response.Buffer = true;
            Response.Clear();
            Response.ClearContent();
            Response.ClearHeaders();
            Response.ContentType = "application/pdf";
            Response.AddHeader(
              "Content-Disposition",
              string.Format("attachment; filename={0}",filename)
            );
            // stream pdf bytes to the browser
            Response.OutputStream.Write(estatement.Document, 0, estatement.Document.Length);
            Response.End();
音盲 2025-01-10 15:00:52

这是我在 stackoverflow 上发表的一篇文章,听起来像是同样的问题。

IE8 及更低版本无法处理缓存控制标头,并导致无法下载 PDF 等静态内容。

链接

Here is a post on stackoverflow that I had which sounds like the same problem.

IE8 and lower cant handle the Cache-control header and causes static content such as PDF's to not get downloaded.

Link

初见 2025-01-10 15:00:52

两件事:

1) 在处理程序中创建响应之前清除所有标头。这为我解决了由 Microsoft 安全公告 MS11-100 引起的问题,其中 Cache-Control 标头被设置为 no-cache="Set-Cookie" (请参阅 这篇博文 了解更多信息):

// snip...

if (estatement.Document != null)
{
    context.Response.ClearHeaders();
    context.Response.Clear();
    context.Response.ContentType = "Application/pdf";
    // snip...

2)我不确定这是否真的会导致任何问题,但与其在每次用户下载 PDF 时创建一个 iframe,为什么不直接设置 window.location 属性?这样,您就不会向文档添加“一次性”iframe,并且行为应该仍然相同:

function EStatementDownload(fileid) {
    window.location = "EStatementFile.ashx?fileid=" + fileid;
}

Two things:

1) Clear all of your headers prior to creating your response in your handler. This solved an issue for me cause by Microsoft Security Bulletin MS11-100 where the Cache-Control header was getting set to no-cache="Set-Cookie" (see this blog post for more info) :

// snip...

if (estatement.Document != null)
{
    context.Response.ClearHeaders();
    context.Response.Clear();
    context.Response.ContentType = "Application/pdf";
    // snip...

2) I'm not sure if this is actually causing any issues, but rather than creating an iframe each time a user downloads a PDF, why not just set the window.location property? This way you're not adding "throw-away" iframes to the document, and the behavior should still be the same:

function EStatementDownload(fileid) {
    window.location = "EStatementFile.ashx?fileid=" + fileid;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文