You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调试未被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

错误根源分析

  1. HTTP版本与URI编码差异:Swagger请求使用HTTP/1.1且路径经过URL编码(%2F),而Docker域名请求使用HTTP/1.0且路径为原始斜杠。Kestrel对HTTP/1.0请求的URI解析逻辑存在差异,未编码的特殊字符可能触发UriFormatException。
  2. 连接复用异常:交替/随机失败模式与连接复用(Keep-Alive)相关,首次连接建立正常,复用连接时后续请求的URI解析出错,导致请求未进入中间件就失败。
  3. 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
    

解决方案

  1. 统一HTTP版本与路径编码:确保Docker侧请求使用HTTP/1.1,并对路径中的斜杠进行URL编码(%2F),避免Kestrel解析错误。
  2. 配置Kestrel URI解析规则:在Program.cs中调整Kestrel配置,允许未编码路径字符:
    builder.WebHost.ConfigureKestrel(serverOptions =>
    {
        serverOptions.ConfigureEndpointDefaults(listenOptions =>
        {
            listenOptions.NoDelay = true;
            // 调整请求行大小限制,允许更长路径
            serverOptions.Limits.MaxRequestLineSize = 8192;
        });
    });
    
  3. 检查Docker代理配置:若使用反向代理(如Nginx),确保代理传递的Host头、路径编码格式正确,避免请求格式失真。

内容的提问来源于stack exchange,提问作者Meir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 22:24:12