使用GetEndPoint方法无响应,不使用则报405错误的原因咨询
ASP.NET Core中自定义中间件导致405错误未正常返回的问题分析
我遇到一个ASP.NET Core的问题,两段代码仅差一个自定义中间件,请求结果却完全不同:
Code 1(带自定义中间件)
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.UseRouting(); app.Use(async (context, next) => { var endPoint = context.GetEndpoint(); if (endPoint != null) { await context.Response.WriteAsync($"EndPoint: {endPoint}\n"); await context.Response.WriteAsync($"Display Name: {endPoint.DisplayName}\n"); await context.Response.WriteAsync($"Request Delegate: {endPoint.RequestDelegate}\n"); await context.Response.WriteAsync($"Meta Data: {endPoint.Metadata}\n"); } await next(context); }); app.UseEndpoints(endpoint => { endpoint.MapGet("map1", async (context) => { await context.Response.WriteAsync("In Map 1"); }); endpoint.MapPost("map2", async (context) => { await context.Response.WriteAsync("In Map 2"); }); }); app.Run(async (context) => { await context.Response.WriteAsync("Neither in Map 1 nor in Map 2"); }); app.Run();
现象:用GET方法请求/map2时,浏览器卡住,Postman报错(无响应或超时)。
Code 2(注释自定义中间件)
using System.ComponentModel.Design.Serialization; using Microsoft.AspNetCore.Authentication; var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.UseRouting(); //app.Use(async (context, next) => //{ // var endPoint = context.GetEndpoint(); // if (endPoint != null) // { // await context.Response.WriteAsync($"EndPoint: {endPoint}\n"); // await context.Response.WriteAsync($"Display Name: {endPoint.DisplayName}\n"); // await context.Response.WriteAsync($"Request Delegate: {endPoint.RequestDelegate}\n"); // await context.Response.WriteAsync($"Meta Data: {endPoint.Metadata}\n"); // } // await next(context); //}); app.UseEndpoints(endpoint => { endpoint.MapGet("map1", async (context) => { await context.Response.WriteAsync("In Map 1"); }); endpoint.MapPost("map2", async (context) => { await context.Response.WriteAsync("In Map 2"); }); }); app.Run(async (context) => { await context.Response.WriteAsync("Neither in Map 1 nor in Map 2"); }); app.Run();
现象:用GET方法请求/map2时,浏览器和Postman均返回405 Method Not Allowed错误,这个结果我能理解,但不知道为什么Code 1不会返回同样的错误,反而出现无响应的情况。
问题原因分析
这是因为自定义中间件提前向响应流写入了内容,打断了ASP.NET Core内置的405错误处理逻辑:
- 请求进入管道后,
UseRouting会完成端点匹配,用GET请求/map2时,路由系统会找到对应的MapPost("map2")端点(虽然该端点只接受POST方法)。 - 在Code 2中,没有自定义中间件,
UseEndpoints会检查请求方法与端点允许的方法是否匹配,发现不匹配后,直接返回405错误,同时自动处理响应状态码、Allow头等头部信息。 - 在Code 1中,自定义中间件在
UseEndpoints之前执行,此时context.GetEndpoint()已经能拿到匹配到的map2端点,中间件直接调用Response.WriteAsync向响应流写入了内容。一旦响应流开始写入,ASP.NET Core就会判定响应已启动,后续UseEndpoints中的405错误处理逻辑会被跳过——因为响应状态和内容已经无法修改。 - 但匹配到的
map2端点的请求委托只处理POST请求,GET请求进入后不会执行任何写入操作,同时后续的app.Run委托也不会触发(因为端点已经匹配成功),导致响应流只写入了中间件的内容,但没有完成响应的收尾,客户端会一直等待直到超时,表现为浏览器卡住、Postman报错。
简单总结:中间件提前启动了响应,让405错误逻辑无法触发,而匹配到的端点又不处理当前请求方法,最终导致响应未完成,客户端超时。
内容的提问来源于stack exchange,提问作者Hamza Bilal
相关产品推荐
相关产品推荐

