如何调试未被UseDeveloperExceptionPage捕获的.NET 500异常
容器中.NET服务请求交替成功/500失败问题排查
问题描述
运行在容器中的.NET服务出现以下异常现象:
- 调用同一接口时,请求交替出现成功与500失败,后续转为随机失败模式
- 输出窗口抛出
System.UriFormatException和System.Net.Http.HttpRequestException异常 - 添加
UseDeveloperExceptionPage未捕获到异常,首个中间件断点从未捕获到失败请求,推测问题出在Kestrel层面 - 通过localhost(Swagger)访问无异常,但使用Docker域名(proxy_backend)访问时出现问题
当前Program.cs配置:
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddHealthChecks(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(); } // Should be the first middleware app.UseHealthChecks("/HealthCheck"); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.Map("/{**catch-all}", async httpContext => { // return 200 if we are healthy here httpContext.Response.StatusCode = 404; return; }); }); Console.WriteLine("Test Version 6"); app.Run(); public partial class Program { } // so you can reference it from tests
补充日志
Swagger正常请求日志
info: Microsoft.AspNetCore.Hosting.Diagnostics[1] Request starting HTTP/1.1 GET http://localhost:50182/category_1a1a1a1a%2Fproduct_2a2a2a2a%2Fid_1123467.product?sig=EEF7952F7B823B6981A797AAE429DF - - trce: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[2] All hosts are allowed. dbug: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[3] The request path does not match the path filter dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1001] 1 candidate(s) found for the request path '/category_1a1a1a1a%2Fproduct_2a2a2a2a%2Fid_1123467.product?sig=EEF7952F7B823B6981A797AAE429DF' dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1005] Endpoint '/{**catch-all}' with route pattern '/{**catch-all}' is valid for the request path '/category_1a1a1a1a%2Fproduct_2a2a2a2a%2Fid_1123467.product?sig=EEF7952F7B823B6981A797AAE429DF' dbug: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[1] Request matched endpoint '/{**catch-all}' info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] Executing endpoint '/{**catch-all}' info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] Executed endpoint '/{**catch-all}' dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[9] Connection id "0HMJER5USLLOE" completed keep alive response. info: Microsoft.AspNetCore.Hosting.Diagnostics[2] Request finished HTTP/1.1 GET http://localhost:50182/category_1a1a1a1a%2Fproduct_2a2a2a2a%2Fid_1123467.product?sig=EEF7952F7B823B6981A797AAE429DF - - - 404 0 - 3126.3906ms The thread 0xf12 has exited with code 0 (0x0). The thread 0xf0f has exited with code 0 (0x0). The thread '.NET ThreadPool Worker' (0xb2) has exited with code 0 (0x0). The thread '.NET ThreadPool Worker' (0xbf) has exited with code 0 (0x0). The thread '.NET ThreadPool Worker' (0xc1) has exited with code 0 (0x0). The thread '.NET ThreadPool Worker' (0xb8) has exited with code 0 (0x0). The thread 0xf14 has exited with code 0 (0x0). The thread 0xf15 has exited with code 0 (0x0). The thread 0xf10 has exited with code 0 (0x0).
浏览器首次正常请求日志
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[39] Connection id "0HMJER5USLLOF" accepted. dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[1] Connection id "0HMJER5USLLOF" started. info: Microsoft.AspNetCore.Hosting.Diagnostics[1] Request starting HTTP/1.0 GET http://proxy_backend/category_1a1a1a1a/product_2a2a2a2a/id_1123467.product?sig=EEF7952F7B823B6981A797AAE429DF - - trce: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[2] All hosts are allowed. dbug: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[3] The request path does not match the path filter dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1001] 1 candidate(s) found for the request path '/category_1a1a1a1a/product_2a2a2a2a/id_1123467.product' dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1005] Endpoint '/{**catch-all}' with route pattern '/{**catch-all}' is valid for the request path '/category_1a1a1a1a/product_2a2a2a2a/id_1123467.product' dbug: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[1] Request matched endpoint '/{**catch-all}' info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] Executing endpoint '/{**catch-all}' info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] Executed endpoint '/{**catch-all}' info: Microsoft.AspNetCore.Hosting.Diagnostics[2] Request finished HTTP/1.0 GET http://proxy_backend/category_1a1a1a1a/product_2a2a2a2a/id_1123467.product?sig=EEF7952F7B823B6981A797AAE429DF - - - 404 0 - 1959.3089ms dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[10] Connection id "0HMJER5USLLOF" disconnecting. dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[2] Connection id "0HMJER5USLLOF" stopped. dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[7] Connection id "0HMJER5USLLOF" sending FIN because: "The Socket transport's send loop completed gracefully." dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[6] Connection id "0HMJER5USLLOF" received FIN.
浏览器失败请求日志
Exception thrown: 'System.UriFormatException' in System.Private.Uri.dll Exception thrown: 'System.UriFormatException' in System.Private.CoreLib.dll Exception thrown: 'System.UriFormatException' in System.Private.CoreLib.dll
错误根源分析
- HTTP版本与URI编码差异:Swagger请求使用HTTP/1.1且路径经过URL编码(
%2F),而Docker域名请求使用HTTP/1.0且路径为原始斜杠。Kestrel对HTTP/1.0请求的URI解析逻辑存在差异,未编码的特殊字符可能触发UriFormatException。 - 连接复用异常:交替/随机失败模式与连接复用(Keep-Alive)相关,首次连接建立正常,复用连接时后续请求的URI解析出错,导致请求未进入中间件就失败。
- Docker网络请求格式问题:Docker域名访问时的请求可能存在格式不规范(如HTTP头缺失、路径编码不一致),引发Kestrel解析失败。
调试与解决步骤
调试方法
- 启用Kestrel详细日志:在
appsettings.json中添加日志配置,查看请求解析阶段的详细错误:{ "Logging": { "LogLevel": { "Microsoft.AspNetCore.Server.Kestrel": "Trace", "Microsoft.AspNetCore.Server.Kestrel.Core": "Trace" } } } - 捕获Kestrel连接异常:在
Program.cs中注册Kestrel异常回调,直接捕获请求解析阶段的错误:builder.WebHost.ConfigureKestrel(serverOptions => { serverOptions.OnConnection(connection => { connection.ConnectionClosed.Register(() => { var errorFeature = connection.Features.Get<Microsoft.AspNetCore.Server.Kestrel.Core.Features.IKestrelConnectionErrorFeature>(); if (errorFeature?.Error != null) { Console.WriteLine($"Kestrel Connection Error: {errorFeature.Error}"); } }); return Task.CompletedTask; }); }); - 模拟异常请求:用curl发送HTTP/1.0请求复现问题:
curl -v --http1.0 http://proxy_backend/category_1a1a1a1a/product_2a2a2a2a/id_1123467.product?sig=EEF7952F7B823B6981A797AAE429DF
解决方案
- 统一HTTP版本与路径编码:确保Docker侧请求使用HTTP/1.1,并对路径中的斜杠进行URL编码(
%2F),避免Kestrel解析错误。 - 配置Kestrel URI解析规则:在
Program.cs中调整Kestrel配置,允许未编码路径字符:builder.WebHost.ConfigureKestrel(serverOptions => { serverOptions.ConfigureEndpointDefaults(listenOptions => { listenOptions.NoDelay = true; // 调整请求行大小限制,允许更长路径 serverOptions.Limits.MaxRequestLineSize = 8192; }); }); - 检查Docker代理配置:若使用反向代理(如Nginx),确保代理传递的
Host头、路径编码格式正确,避免请求格式失真。
内容的提问来源于stack exchange,提问作者Meir
相关产品推荐
相关产品推荐

