POST 请求的 GENERAL_REQUEST_ENTITY 期间的错误导致 ASP .NET 会话状态永远不会被解锁

Posted

技术标签:

【中文标题】POST 请求的 GENERAL_REQUEST_ENTITY 期间的错误导致 ASP .NET 会话状态永远不会被解锁【英文标题】:Error during GENERAL_REQUEST_ENTITY for POST request causes ASP .NET session state to never get unlocked 【发布时间】:2013-10-16 18:35:44 【问题描述】:

(来自服务器故障的交叉发布,我没有得到任何牵引力): 我一直在尝试找出导致 Web 请求由于意外错误而终止后 ASP .NET 会话状态保持锁定状态的根本原因。我们使用 SQL Server 会话状态提供程序进行会话,因为我们在 Web 场中有多个服务器。这个问题首先表现为许多请求无缘无故地卡在其生命周期的“AcquireRequestState”事件中。我能够在 SQL Server 的会话状态数据库中找到这些请求的相应条目,这些条目都被锁定(列 Locked = 1)。我还能够将这些请求与 IIS 日志中的条目相关联,HTTP 状态代码为 500(子状态为 0)。这些发现让我相信,在某些情况下,请求会出错,但并未像应有的那样释放其对会话状态的锁定。

我在 IIS 中为有问题的网站启用了失败的请求跟踪,状态代码为 500,所有可用的提供程序都被选中,每个提供程序都使用“详细”设置进行详细设置。我已经收集了几个导致永久锁定 ASP .NET 会话的失败跟踪。它们都具有相同的特征:

它们都是“POST”请求,浏览器在其中发布要处理/保存的数据。 它们都有事件表明在 REQUEST_ACQUIRE_STATE 事件期间调用了“会话”模块。此时,请求会将会话状态数据库中的行标记为“锁定”。这是正常的,也是意料之中的。 它们都有 GENERAL_READ_ENTITY_START、GENERAL_READ_ENTITY_END 和 GENERAL_REQUEST_ENTITY 条目,这些条目似乎正在读取作为请求的一部分发布到服务器的数据。这似乎是一种缓冲操作,因为这些事件会一遍又一遍地重复,每个事件都会读取已发布数据的某些子集。 在“读取实体”相关事件期间的某个时间点会发生错误。有些有错误代码“函数不正确。(0x80070001)”,而另一些则有“I/O 操作已因线程退出或应用程序请求而中止。(0x800703e3)”。 一旦遇到错误,它们都会直接跳转到 END_REQUEST 事件。

这里的问题是,在正常情况下,应该有一个 RELEASE_REQUEST_STATE 事件允许 Session 模块释放它对会话的锁定。在这种情况下将跳过此事件。可以肯定的是,我还为“200”状态代码启用了失败的请求跟踪,并生成了多个成功请求的跟踪,这些请求确实由 Session 模块处理了 RELEASE_REQUEST_STATE 事件。

一位同事指出,您还可以通过调用 HttpContext.Current.ApplicationInstance.CompleteRequest() 使请求直接跳到“END_REQUEST”事件。我对此进行了测试,发现在发布请求期间使用此方法创建的跟踪与我在此问题发生时捕获的跟踪非常相似,但会话仍然得到正确清理。这导致我在存储会话的 SQL Server 数据库上运行 SQL Profiler,以跟踪对存储过程的所有调用。当我们由于调用 CompleteRequest() 而直接跳到 END_REQUEST 时,会按预期进行调用以更新会话状态(并释放锁)。当我们在 GENERAL_REQUEST_ENTITY 期间由于错误而跳到 END_REQUEST 时,永远不会调用更新或释放会话状态的锁定。

此时我的理论是某种网络问题导致“功能不正确”和“I/O 操作因线程退出或应用程序请求而中止”错误,但我不明白为什么这似乎导致请求处理跳过释放会话状态的锁定。如果请求通过 REQUEST_ACQUIRE_STATE 似乎它也应该在请求结束时的某个时刻释放锁。我不愿意说这是 IIS 或 ASP .NET 中的一个错误,但在这一点上对我来说确实是这样。

是否存在任何已知的错误会导致会话状态锁不被释放的情况?

【问题讨论】:

【参考方案1】:

事实证明,这与这个问题有关:ManagedPipelineHandler for an AJAX POST crashes if an IE9 user navigates away from a page while that call was in progress

在该问题的已接受答案中指定的解决方法确实有效,但微软还发布了一个修补程序(在撰写本文时尚未公开提供),该修补程序修补了会话处理逻辑,以避免一起出现问题。

【讨论】:

以上是关于POST 请求的 GENERAL_REQUEST_ENTITY 期间的错误导致 ASP .NET 会话状态永远不会被解锁的主要内容,如果未能解决你的问题,请参考以下文章

post请求用啥mapping

python用socket模拟post请求

如何使用 _csrf 在 angularjs 中发送 POST 请求?

如何使用 $_GET 或 $_POST 变量来区分每种类型的请求? [复制]

从 $_POST 请求(不是来自 URL)使用 ParamConverter

存储$ _GET并在POST请求中再次使用它