.NET 6请求取消后中间件无法拦截响应体的原因
请求取消后中间件无法获取响应体的原因解析
问题描述
在.NET 6 Web API中编写了用于处理响应体的中间件,发现若在处理完成前请求被取消,中间件会获取到空的响应体。将处理逻辑迁移到Action过滤器后,即便请求被取消,仍能成功获取响应体。
中间件代码
public class CustomResponseMiddleware { private readonly RequestDelegate _next; public CustomResponseMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext httpContext) { var originalBodyStream = httpContext.Response.Body; await using var memoryStream = new MemoryStream(); httpContext.Response.Body = memoryStream; await _next(httpContext); memoryStream.Seek(0, SeekOrigin.Begin); // The responseBody will be as empty string ("") var responseBody = await new StreamReader(memoryStream).ReadToEndAsync(); memoryStream.Seek(0, SeekOrigin.Begin); //Do some processing on the response body here httpContext.Response.Body = originalBodyStream; await httpContext.Response.Body.WriteAsync(memoryStream.ToArray()); } }
原因解析
核心差异在于中间件与Action过滤器在请求处理管道中的执行时机和所处层级不同,以及ASP.NET Core对请求取消的处理逻辑差异:
中间件的执行层级与请求取消的影响
中间件处于整个请求处理管道的链式执行流程中,await _next(httpContext)会将请求传递到后续中间件直至MVC框架。当请求被取消(如客户端断开连接),ASP.NET Core触发HttpContext.RequestAborted取消令牌,此时MVC框架会直接终止响应写入流程——既然客户端已经不需要响应,就不会把生成好的响应内容写入你替换的memoryStream,导致后续读取到空内容。Action过滤器的执行时机
Action过滤器属于MVC框架内部的生命周期环节,它在动作方法执行完成、响应内容已生成后运行。此时不管后续请求是否被取消,过滤器已经能拿到动作方法生成的完整响应体(MVC会先完成响应内容生成,再处理请求取消的后续逻辑),因此即便请求被取消,依然可以正常获取响应体。中间件代码的潜在问题
你的中间件未处理请求取消引发的OperationCanceledException,当_next因请求取消抛出异常时,后续读取流的代码可能无法执行,或者流本身就没有被写入任何内容。
内容的提问来源于stack exchange,提问作者Kitty Chen
相关产品推荐
相关产品推荐

