从ASP.NET Web处理程序(.ashx)下载文件时的错误处理

7
我有一个网页,用户可以通过ASP.NET Web处理程序(.ashx)下载PDF文件。它的实现方式类似于此问题中的答案。我的问题是,当我在JavaScript中执行window.top.location.href = url;时,如果处理程序抛出异常,我实际上无法控制发生了什么。当一切正常工作时,用户的体验是他们基本上停留在原来的页面上,浏览器告诉他们可以下载PDF文件。然而,在处理程序中抛出异常时,他们将被重定向到处理程序的URL并显示空白页面。
以下是一些示例代码,以使其更加清晰:
JavaScript:
function openPDF() {
    var url = GeneratePDFUrl();
    window.top.location.href = url;
}

处理器:

public override void Process(HttpContext context)
{
    byte[] pdfdata = GetPDFData();
    context.Response.ContentType = "application/pdf";
    context.Response.AddHeader("content-disposition", "attachment; filename=\"" + GetPDFFileName() + "\"");
    context.Response.AddHeader("content-length", pdfdata.Length.ToString());
    context.Response.BinaryWrite(pdfdata);
}

当GetPDFData()抛出异常时会出现问题。我们正在尽力避免GetPDFData()抛出异常,但由于其源自用户输入,因此在这里处理它以防止出现我们无法预测的错误。以下是我提出的一种解决方案,但它会显示用户的错误文本(而不是空白页面)。
public override void Process(HttpContext context)
{
    try
    {
        byte[] pdfdata = GetPDFData();
        WritePDF(pdfdata, GetPDFFileName()); // Executes code in example above
    }
    catch (Exception e)
    {
        context.Response.Clear();
        context.Response.Write(GetErrorMessage(e));
    }
}

理想情况下,我希望向用户显示一个弹出窗口,以便他们留在原来的页面。

如果您已经将标题作为PDF发送,则很难给出其他消息,除了发送一个页面错误代码,例如“页面未找到”,但是如果您没有将标题作为PDF发送,并且文件名标题,则可以编写一条消息,就像您所做的那样。现在,在对话框中停留在页面上是不可能的,因为您已经转到其他页面,第一页不再具有控制权。 - Aristos
2个回答

7
首先,在我的这个答案中,用户问如何使用javascript进行下载。但是如果你已经有了链接,就不必使用javascript,你也可以使用普通的下载链接。
现在许多网站使用一个页面,上面有一些文字,例如“现在您的下载将在几秒钟内开始。如果没有开始,请单击此处等等”。其中一个原因与您的问题类似,用户必须知道某些东西将在几秒钟后开始下载,如果没有,那么用户就会理解出现了问题,而无需其他额外的消息。
一般来说,当您要发送文件进行下载时,您已经不在该页面上了,您无法在下载过程中发送消息,或者当文件以pdf结尾时,它可能不会在网页上显示任何内容。因此从我的角度来看,如果您遇到问题并抛出异常,则需要设计一些步骤来告知用户出现了问题,例如中间页面会提示用户“现在您将收到一个文件——如果文件未在几秒钟内开始下载,请执行此操作”。

然而,当处理程序中出现异常时,他们会被重定向到处理程序的URL,并显示一个空白页面。

为了避免这个黑色页面,在错误发生时,您可以返回该代码,用户仍停留在当前页面,但仍然没有收到任何错误消息。
Response.TrySkipIisCustomErrors = true;
Response.Status = "204 No Content";
Response.StatusCode = 204;
Response.End();

如果出现异常,您可以尝试使用

redirect

将用户重定向到错误页面。

Response.Redirect("errorpage.aspx");

也许你可以将一些错误标识发送过来。

你还可以尝试展示一个简单的消息,例如:

context.Response.ContentType = "text/html";
context.Response.Write("Error downloading file - Please contact with us");

1
谢谢您的回复 - 我们选择了您的 Response.Redirect 作为答案。 - Steve

3

如果不设置窗口的href,而是设置隐藏iframe的src,会怎么样呢?然后你可以在隐藏的iframe中对返回值进行一些诡计,比如:

context.Response.Clear();
context.Response.Write("<script>alert('" + GetErrorMessage(e) + "');</script>");

这个简单的例子只会弹出错误信息。如果你在同一个域名下(我猜你是!),那么可以更聪明地处理,不要弹出警告,而是调用父级中的方法,例如:
context.Response.Clear();
context.Response.Write("<script>window.parent.someFunction('" + GetErrorMessage(e) + "');</script>");

我在 Stack Overflow 上找到了一个例子,可以实现这个功能:使用 JavaScript 从加载的 iframe 中检索 HTTP 状态代码

虽然这是用于上传而非下载,但概念相同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接