![POST 的 GENERAL_REQUEST_ENTITY 期间出错导致 ASP .NET 会话状态永远无法解锁](https://linux22.com/image/804732/POST%20%E7%9A%84%20GENERAL_REQUEST_ENTITY%20%E6%9C%9F%E9%97%B4%E5%87%BA%E9%94%99%E5%AF%BC%E8%87%B4%20ASP%20.NET%20%E4%BC%9A%E8%AF%9D%E7%8A%B6%E6%80%81%E6%B0%B8%E8%BF%9C%E6%97%A0%E6%B3%95%E8%A7%A3%E9%94%81.png)
我一直在尝试找出导致 ASP .NET 会话状态在 Web 请求由于意外错误而终止后仍保持锁定状态的根本原因。我们使用 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”状态代码的失败请求跟踪,并生成了几个成功请求的跟踪,这些请求确实具有由会话模块处理的 RELEASE_REQUEST_STATE 事件。
我目前的理论是,某种网络问题导致了“函数错误”和“由于线程退出或应用程序请求而导致 I/O 操作中止”错误,但我不明白为什么这似乎会导致请求处理跳过 RELEASE_REQUEST_STATE 事件。如果请求经过 REQUEST_ACQUIRE_STATE,它似乎也应该命中 RELEASE_REQUEST_STATE。我不愿意说这是 IIS 或 ASP .NET 中的一个错误,但目前在我看来确实如此。
我可以进行任何配置更改来帮助确保在所有错误条件下触发“RELEASE_REQUEST_STATE”吗?