如何不中止 http 响应 c#
本文关键字:响应 http 何不中 | 更新日期: 2023-09-27 18:35:33
在将文件发送给用户进行下载后,我需要运行几个方法。发生的情况是,在我向用户发送文件后,响应中止,response.end()
后我无法再执行任何操作。
例如,这是我的示例代码:
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=test.pdf");
Response.ContentType = "application/pdf";
byte[] a = System.Text.Encoding.UTF8.GetBytes("test");
Response.BinaryWrite(a);
Response.End();
StartNextMethod();
Response.Redirect(URL);
因此,在此示例中,StartNextMethod
和 Response.Redirect
未执行。
我尝试的是使用以下代码创建了一个单独的处理程序(ashx):
public void ProcessRequest(HttpContext context)
{
context.Response.Clear();
context.Response.AddHeader("content-disposition", "attachment; filename=test.pdf");
context.Response.ContentType = "application/pdf";
byte[] a = System.Text.Encoding.UTF8.GetBytes("test");
context.Response.BinaryWrite(a);
context.Response.End();
}
并像这样称呼它:
Download d = new Download();
d.ProcessRequest(HttpContext.Current);
StartNextMethod();
Response.Redirect(URL);
但同样的错误发生了。我尝试用CompleteRequest替换Response.End,但它没有帮助。
我想问题是我正在使用HttpContext.Current,但应该使用单独的响应流。这是对的吗?我如何在单独的方法中通常执行此操作(假设我希望我的处理程序接受数据和内容类型的字节数组,并且可以从单独的响应下载。我真的不想使用单独的页面进行响应。
更新
我仍然没有找到一个好的解决方案。我想在用户下载文件后执行一些操作,但不要使用单独的页面进行响应''请求。
更新
既然你说没有第二页,那就这样做吧。 向页面添加一个部分,用于检查查询字符串参数(如 fileid 或路径等)。 如果此值存在,则它使用现有代码启动下载过程。 如果此值不存在,则它正常运行。
现在,当用户单击下载链接时,您将执行回发(您已经在执行)。在此回发中,在页面上创建一个 iFrame,并使用添加的查询字符串参数(mypage.aspx?id=12664 或 ?download=true,类似的东西)将 iFrame 的 URL 设置为页面 URL。 创建 iframe 后,执行任何额外的数据绑定/等...你也希望。
例
- http://encosia.com/ajax-file-downloads-and-iframes/
上面链接的示例使用 iFrame 和更新面板,就像您所说的那样。
原始帖子
Response.Flush 将允许您在将文件发送给用户后继续处理,或者只是不调用 Response.End(您也不需要)。
但是Daniel A. White是正确的,发送文件后实际上无法从代码重定向,如果您尝试,则会出现错误。 但是,如果需要,您可以继续执行其他服务器端操作。
其他答案与普遍共识一致,文件开始下载后无法重定向:https://stackoverflow.com/a/822732/328968(PHP,但概念相同,因为它通常涉及HTTP)。 或下载文件后定向到新页面。
Response.End() 抛出线程中止异常。它旨在结束您的响应。之后的任何代码都不会在该线程中处理。
End 方法使 Web 服务器停止处理脚本并返回当前结果。不处理文件的其余内容。
你想实现什么目标?
如果你的目的是允许pdf下载,然后将用户带到其他页面,一个小javascript可以帮助你。
添加一个带有计时器的脚本,以将 location.href 设置为重定向的分页。
正如前面的答案所述 - 返回PDF文件意味着发送HTTP标头。在那之后你不能发送另一个标头,Response.Redirect() 只是意味着发送 HTTP 302。
如果您不想使用单独的页面,或者不想使用 AJAX,为什么不尝试:
<head>
<meta http-equiv="refresh" content="3; url=http://www.site.com/download.aspx?xxxx">
</head>
实际上,这将显示您要向用户显示的所需页面,并将在 3 秒后使用下载 PDF 文件的 URL 刷新页面。
分块下载文件,如图所示 ASP.NET 中的文件下载 和 跟踪下载成功/失败的状态 或在此问题的答案中。当文件的最后一个区块写入客户端时,您可以执行所需的代码。(不必在最后,可以根据您的需要介于两者之间的任何地方。
单击WebForm1.aspx
上的下载按钮即可开始下载文件。 然后,在文件下载完成后(由WebForm2.aspx
提供),用户会自动重定向。
WebForm1.aspx
<script type="text/javascript">
$(document).ready(function () {
$('#btnDL').click(function () {
$('body').append('<iframe src="WebForm2.aspx" style="display:none;"></iframe>');
return true;
});
});
</script>
<asp:Button runat="server" ID="btnDL" ClientIDMode="Static" Text="Download" OnClick="btnDL_Click" />
WebForm1.aspx.cs
protected void btnDL_Click(object sender, EventArgs e)
{
var sent = Session["sent"];
while (Session["sent"]==null)
{// not sure if this is a bad idea or what but my cpu is NOT going nuts
}
StartNextMethod();
Response.Redirect(URL);
}
WebForm2.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=test.pdf");
Response.ContentType = "application/pdf";
byte[] a = System.Text.Encoding.UTF8.GetBytes("test");
Response.BinaryWrite(a);
Session["sent"] = true;
}
Global.asax.cs
protected void Session_Start(object sender, EventArgs e)
{
Session["init"] = 0; // init and allocate session data storage
}
注意:请确保不要使用 ASX(泛型处理程序)来提供下载服务。 出于某种原因,ASX 和 ASPX 中的会话不会相互通信,除非您实现了这一点。
只需删除context.Response.End();
,因为无论如何您都在重定向...
问题是这里的逻辑有缺陷。为什么要结束响应?
获取 PDF 并显示指向它的链接,或使用META
刷新重定向到 PDF 的位置,或者您也可以显示链接或使用这两种技术的组合。
你正在尝试的是行不通的。
这就是我要做的:
- 在本地将内容写入文件并为其分配唯一 ID
- 将用户发送到包含隐藏框架的下一页,该隐藏框架使用唯一 ID (JavaScript) 执行请求
- 隐藏请求页面加载文件并在内容流上推送。
这与许多文件下载站点使用的行为相同。唯一的问题是,如果隐藏帧失败(javascript 关闭)来执行请求,为什么如果自动请求失败,为什么许多相同的站点都有可用的链接。
缺点:文件清理。
我推荐这个解决方案:
-
不要使用响应。结束();
-
声明这个全局变量:bool isFileDownLoad;
-
就在你(Response.BinaryWrite(a);)之后set ==> isFileDownLoad = true;
-
覆盖您的渲染,例如:
///AEG:处理线程中止异常非常重要//////覆盖受保护的void Render(HtmlTextWriter w){ if (!isFileDownLoad) base.渲染(w);}