【问题标题】:IE7/8: PDF file won't download with HTTP GETIE7/8:使用 HTTP GET 无法下载 PDF 文件
【发布时间】:2012-02-29 10:29:26
【问题描述】:

我正在使用 DataGridView 来显示语句列表。其中一列是 LinkBut​​ton,它允许您以 PDF 格式下载该特定语句。我的代码在所有浏览器中都能完美运行,除了 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>

Grid 的 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();
        }
    }

单击网格上的链接按钮时,Firebug 中会显示以下 javascript 信息,这可能有助于查找问题:

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

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

可能与 iFrame 有关?

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

【问题讨论】:

  • 您在 IE7/8 中看到了什么行为?
  • 当我点击链接按钮时,什么也没有发生...没有下载文件对话框。
  • 要在调用 Response.End() 时忽略 ThreadAbortException,您需要添加一个 try catch 并忽略该异常。尝试 { Response.End(); } catch(Exception ex) { if(ex is ThreadAbortException) { // 什么也不做 } else { throw; } }

标签: c# javascript asp.net ajax pdf


【解决方案1】:

你能试试这个吗-

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

【讨论】:

  • 您的代码在所有浏览器中都能完美运行,但在 IE7 或 IE8 中仍然无法运行。文件下载对话框仍未显示:(
  • 你可以尝试使用 window.open ScriptManager.RegisterStartupScript(this, this.GetType(), "redirectScript", string.Format("window.open('{0}','_blank') ;",handlerUrl), true);代替 window.location ,其中 handlerUrl 是您的 ashx url
【解决方案2】:

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

IE8 及更低版本无法处理 Cache-control 标头并导致 PDF 等静态内容无法下载。

Link

【讨论】:

  • 我尝试删除 Cache-control 标头,但同样的事情发生了......这没什么。
【解决方案3】:

两件事:

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

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

【讨论】:

  • 谢谢,window.location 是一种比使用 iFrame 更好的方法。它仍然不能解决问题,但我认为这是一种增强。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-08
相关资源
最近更新 更多