授权需求处理器读取HttpRequest.Body导致路由匹配失效如何解决
问题根因
你遇到的现象本质是请求体读取逻辑破坏了后续ASP.NET Core的参数绑定流程,核心问题有三个:
StreamReader默认在释放时会关闭底层的请求体流,哪怕开了请求缓冲,后续MVC绑定[FromBody]参数时也无法读取已关闭的流,导致参数绑定失败。- 读取完请求体后没有手动将流的位置重置到起始点,后续读取操作从流末尾开始,只能读到空内容,同样会引发参数绑定失败。
- 用
ReadToEndAsync().Result同步阻塞调用,在ASP.NET Core的请求上下文中容易引发死锁,导致请求流程异常。
参数绑定失败后,ASP.NET Core会判定没有适配当前请求的端点,就会表现出如同路由不匹配、端点无法命中的现象。
修正方案
按照如下规则调整授权处理器代码即可:
- 把同步读取改为异步
await调用,避免死锁 - 创建
StreamReader时指定leaveOpen: true,禁止释放时关闭底层请求流 - 读取完请求体后立刻将
request.Body.Position重置为0 - 确保
EnableBuffering()在第一次读取请求体前调用
修正后代码
// 方法改为async异步实现 protected override async Task HandleRequirementAsync( AuthorizationHandlerContext context, AwoRequirement requirement) { HttpRequest request = Accessor.HttpContext.Request; string awo = request.Headers .SingleOrDefault(a => a.Key == "awo").Value.ToString(); // 开启请求缓冲,必须在第一次读取流之前调用 request.EnableBuffering(); // 配置StreamReader不关闭底层流,leaveOpen设为true using StreamReader stream = new StreamReader( request.Body, encoding: Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true); // 异步读取请求体,避免同步阻塞 string body = await stream.ReadToEndAsync(); // 重置流位置到起始点,供后续参数绑定逻辑读取 request.Body.Position = 0; Thing thing = JsonSerializer.Deserialize<Thing>(body); bool authorized = true; if (thing?.IsBad() == true) { authorized = false; } if (authorized) context.Succeed(requirement); else context.Fail(); }
额外注意事项
如果业务中存在较大的请求体,建议在服务配置中限制请求缓冲的最大大小,避免内存溢出:
// Program.cs 中添加配置 builder.Services.Configure<Microsoft.AspNetCore.Http.Features.FormOptions>(options => { // 示例限制最大缓冲请求体为10MB,可根据业务调整 options.BufferBodyLengthLimit = 10 * 1024 * 1024; });
内容的提问来源于stack exchange,提问作者Konrad Viltersten
相关产品推荐
相关产品推荐

