C# HttpResponse.End 与 HttpResponse.Close 与 HttpResponse.SuppressContent

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1886729/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 21:39:31  来源:igfitidea点击:

HttpResponse.End vs HttpResponse.Close vs HttpResponse.SuppressContent

c#.netasp.netresponse

提问by AdaTheDev

Within an ASPX page, I want to end the response at specific points (not due to an error condition), depending on code path, so that nothing else is sent back down the stream. So naturally used:

在 ASPX 页面中,我想在特定点(不是由于错误条件)结束响应,具体取决于代码路径,这样就不会再将其他任何内容发送回流中。所以很自然地使用:

Response.End();

This results in a ThreadAbortException, which is by design.

这会导致 ThreadAbortException,这是设计使然。

The following seems to work but does not look like the correct approach as per this SO question:

以下似乎有效,但看起来不像这个 SO question的正确方法:

Response.Flush();
Response.Close();

So, how about this?

那么,这个怎么样?

Response.Flush();
Response.SuppressContent = true

and then just let the page complete normally.

然后让页面正常完成。

I could just handle and swallow the ThreadAbortException, but I just want to find out if there is anything wrong/gotchas with the SuppressContent approach?

我可以处理并吞下 ThreadAbortException,但我只想找出 SuppressContent 方法是否有任何错误/问题?

Edit:To give a bit more of an example. Say I have a ASPX page whereby I may change the content-type to one of a number of possibilities. Depending on the content-type and scenario, at a given point in the code I want to prevent any more content from being sent to the client. Assume after SuppressContent has been set set to true, that there is no issue with any further server-side code running. I just don't want anything else to be sent to the client.

编辑:再举一个例子。假设我有一个 ASPX 页面,我可以将内容类型更改为多种可能性之一。根据内容类型和场景,在代码中的给定点,我想防止将更多内容发送到客户端。假设在将 SuppressContent 设置为 true 之后,运行任何进一步的服务器端代码都没有问题。我只是不希望将任何其他内容发送给客户。

Edit 2:MyPage.aspx - has a master page which may include standard content, headers, footers etc etc. This page can just render as a normal page. It also can just write out an (e.g.) XML document to be downloaded. If writing out an XML document (determined on page load), it will clear the ouput, set the content-type to XML, write all the XML out and then if left normally, you end up with the rest of the ASPX page rendering being tacked on to the end - that is obviously not required/breaks the XML.

编辑 2:MyPage.aspx - 有一个母版页,其中可能包括标准内容、页眉、页脚等。该页面可以作为普通页面呈现。它也可以只写出(例如)要下载的 XML 文档。如果写出一个 XML 文档(在页面加载时确定),它将清除输出,将内容类型设置为 XML,写出所有的 XML,然后如果正常保留,您最终会得到 ASPX 页面呈现的其余部分附加到最后 - 这显然不是必需的/破坏了 XML。

Edit 3:For now I'm using the SuppressContent approach. To try and draw this question to a close, I'm raising a bounty and will put the question another way: When shouldyou use SuppressContent? Why would you use it instead of Response.End?

编辑 3:现在我正在使用 SuppressContent 方法。为了尝试结束这个问题,我提出了一个悬赏,并将以另一种方式提出问题:您应该何时使用 SuppressContent?为什么要使用它而不是 Response.End?



Please see the answer I provided below for the solution I actually ended up with as I eventually found a way to avoid the ThreadAbortException when using Response.End. I had already excepted an answer by this point.

请参阅我在下面提供的答案,了解我最终得到的解决方案,因为我最终找到了一种在使用 Response.End 时避免 ThreadAbortException 的方法。到目前为止,我已经排除了一个答案。



采纳答案by eglasius

update - warning: there is a better method, don't use this, see Ethan's answer instead!

更新 - 警告:有更好的方法,不要使用此方法,请参阅 Ethan 的答案!

I wouldn't say there is a valid reason to avoid the Response.End. Wanting to avoid the cost of the ThreadAbortException, by letting the page request cycle go on and have it do extra work that isn't necessary doesn't seem right.

我不会说有一个有效的理由来避免 Response.End。想要避免 ThreadAbortException 的成本,通过让页面请求循环继续并让它做一些不必要的额外工作似乎是不对的。

ThreadAbortException is a special type of exception meant to stop a thread from execution (its re-thrown automatically even if caught). That said, there are some scenarios where it could do harm (see community content added at the end of ThreadAbortException).

ThreadAbortException 是一种特殊类型的异常,旨在阻止线程执行(即使被捕获也会自动重新抛出)。也就是说,在某些情况下它可能会造成伤害(请参阅在ThreadAbortException末尾添加的社区内容)。

Unless you are in one of those scenarios you should stick to Response.End. Note that some usages around, do a SuppressContent & Response.End, I guess in cases that you want to avoid some stuff that would come from the internal Response.Flush.

除非您处于这些场景之一,否则您应该坚持使用 Response.End。注意周围的一些用法,做一个 SuppressContent 和 Response.End,我猜在你想避免一些来自内部 Response.Flush 的东西的情况下。

回答by k?e?m?p? ?

What if, after calling Response.SuppressContent = trueyour page goes on to make changes to a record in the database?

如果在调用Response.SuppressContent = true您的页面后继续对数据库中的记录进行更改会怎样?

回答by Fredrik Haglund

As far as I can understand the code when reflecting HttpResponse using the Flush/SuppressContent approach will make you vulnerable to code trying to do header changes after flush. Changing a header after flush will give a HttpException.

据我所知,使用 Flush/SuppressContent 方法反映 HttpResponse 时的代码会使您容易受到在刷新后尝试更改标头的代码的影响。刷新后更改标头将产生 HttpException。

I would use Response.End() to be absolutely sure that nothing else could interfere with the response.

我会使用 Response.End() 来绝对确保没有其他东西会干扰响应。

If you want to continue execution but also short circuit the http pipeline consider using Response.Flush() and HttpContext.Current.ApplicationInstance.CompleteRequest() like Response.End() does when the context is not in a cancellable period.

如果您想继续执行但也使 http 管道短路,请考虑使用 Response.Flush() 和 HttpContext.Current.ApplicationInstance.CompleteRequest() 就像 Response.End() 在上下文不在可取消期间时所做的那样。

回答by Nick Berardi

This is a very common question. And it is almost always a mistake to call anything except Response.End(). Here is the description of End()from MSDN:

这是一个很常见的问题。除了Response.End(). 这是MSDN中End()的描述:

Sends all currently buffered output to the client, stops execution of the page, and raises the EndRequest event.

将所有当前缓冲的输出发送到客户端,停止页面的执行,并引发 EndRequest 事件。

This seems to be exactly what you want to do. And you will notice in the last part that it raises the EndRequest event. This means that after End() is called, all data is flushed to the client that has been written before the End(), the socket is closed, and resources are freed, and your program stops processing the request right away.

这似乎正是您想要做的。您会在最后一部分注意到它引发了 EndRequest 事件。这意味着在调用 End() 之后,所有数据都将刷新到在 End() 之前已写入的客户端,关闭套接字并释放资源,并且您的程序立即停止处理请求。

回答by Pedro

Are you sure the design strategy is correct? What pre-processing can you do to ensure the correct headers are sent, then stick to it until the script has dispensed its objectives?

你确定设计策略是正确的吗?你可以做哪些预处理来确保发送正确的标头,然后坚持下去直到脚本分配了它的目标?

回答by AdaTheDev

I eventually found a simple solution to using Response.End() without getting a ThreadAbortException.

我最终找到了一个简单的解决方案来使用 Response.End() 而不会出现 ThreadAbortException。

Response.Flush();
Response.End();

From my original question, I'd always been trying JUST a Response.End() after sending some content to the response stream.

从我最初的问题来看,在将一些内容发送到响应流后,我一直在尝试使用 Response.End() 。

It seems that if there is unflushed content when you do Response.End(), you get the ThreadAbortException. By doing the Flush immediately before the End, a ThreadAbortException does not actually get thrown.

似乎如果在执行 Response.End() 时有未刷新的内容,则会收到 ThreadAbortException。通过在 End 之前立即执行 Flush,实际上不会抛出 ThreadAbortException。

Seems to be working great - no ThreadAbortException is being thrown now when I use Response.End

似乎工作得很好 - 当我使用 Response.End 时,现在没有抛出 ThreadAbortException

回答by Eyeball

I know this is an old question, but I'm including this for the benefit of anyone who might stumble into this post. I've been chasing down a bug that led me to review my use of Response.End, and discovered an MSDN post from a year after this question that could be summarized as "Never, ever use Response.End". Here's what Thomas Marquardt, who designed the Integrated Pipeline for IIS7, says about it:

我知道这是一个老问题,但我将这个问题包括在内是为了任何可能偶然发现这篇文章的人的利益。我一直在追查一个错误,该错误导致我回顾了我对 Response.End 的使用,并发现了这个问题一年后的 MSDN 帖子,可以将其总结为“永远不要使用 Response.End”。以下是为 IIS7 设计集成管道的 Thomas Marquardt 对此的评价:

The End method is also on my “never use” list. The best way to stop the request is to call HttpApplication.CompleteRequest. The End method is only there because we tried to be compatible with classic ASP when 1.0 was released. Classic ASP has a Response.End method that terminates processing of the ASP script. To mimic this behavior, ASP.NET's End method tries to raise a ThreadAbortException. If this is successful, the calling thread will be aborted (very expensive, not good for performance) and the pipeline will jump ahead to the EndRequest event. The ThreadAbortException, if successful, of course means that the thread unwinds before it can call any more code, so calling End means you won't be calling any code after that. If the End method is not able to raise a ThreadAbortException, it will instead flush the response bytes to the client, but it does this synchronously which is really bad for performance, and when the user code after End is done executing, the pipeline jumps ahead to the EndRequest notification. Writing bytes to the client is a very expensive operation, especially if the client is halfway around the world and using a 56k modem, so it is best to send the bytes asynchronously, which is what we do when the request ends the normal way. Flushing synchronously is really bad. So to summarize, you shouldn't use End, but using CompleteRequest is perfectly fine. The documentation for End should state that CompleteRequest is a better way to skip ahead to the EndRequest notification and complete the request.

End 方法也在我的“从不使用”列表中。停止请求的最好方法是调用 HttpApplication.CompleteRequest。End 方法之所以存在,是因为我们在 1.0 发布时试图与经典 ASP 兼容。经典 ASP 有一个 Response.End 方法来终止 ASP 脚本的处理。为了模仿这种行为,ASP.NET 的 End 方法尝试引发 ThreadAbortException。如果成功,调用线程将被中止(非常昂贵,不利于性能)并且管道将跳转到 EndRequest 事件。ThreadAbortException,如果成功,当然意味着线程在它可以调用更多代码之前展开,因此调用 End 意味着您将不会在此之后调用任何代码。如果 End 方法无法引发 ThreadAbortException,相反,它会将响应字节刷新到客户端,但它是同步执行的,这对性能来说非常不利,并且当 End 之后的用户代码执行完毕时,管道会跳转到 EndRequest 通知。向客户端写入字节是一项非常昂贵的操作,特别是如果客户端在地球的另一端并且使用 56k 调制解调器,因此最好异步发送字节,这就是我们在请求以正常方式结束时所做的。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 完全没问题。End 的文档应说明 CompleteRequest 是跳过 EndRequest 通知并完成请求的更好方法。当 End 之后的用户代码执行完毕时,管道将跳转到 EndRequest 通知。向客户端写入字节是一项非常昂贵的操作,特别是如果客户端在地球的另一端并且使用 56k 调制解调器,因此最好异步发送字节,这就是我们在请求以正常方式结束时所做的。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 完全没问题。End 的文档应说明 CompleteRequest 是跳过 EndRequest 通知并完成请求的更好方法。当 End 之后的用户代码执行完毕时,管道会向前跳转到 EndRequest 通知。向客户端写入字节是一项非常昂贵的操作,特别是如果客户端在地球的另一端并且使用 56k 调制解调器,因此最好异步发送字节,这就是我们在请求以正常方式结束时所做的。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 完全没问题。End 的文档应说明 CompleteRequest 是跳过 EndRequest 通知并完成请求的更好方法。所以最好异步发送字节,这就是我们在请求以正常方式结束时所做的。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 完全没问题。End 的文档应说明 CompleteRequest 是跳过 EndRequest 通知并完成请求的更好方法。所以最好异步发送字节,这就是我们在请求以正常方式结束时所做的。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 完全没问题。End 的文档应说明 CompleteRequest 是跳过 EndRequest 通知并完成请求的更好方法。

From http://blogs.msdn.com/b/aspnetue/archive/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation.aspx

来自http://blogs.msdn.com/b/aspnetue/archive/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation.aspx