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

.NET 8中间件调用_next后状态码莫名从200变204求助

.NET 8 + FastEndpoints:中间件中状态码从200变为204的问题解决

问题根源

你的问题核心在于FastEndpoints框架的自动响应处理机制:
当你继承Endpoint<TRequest, TResponse>基类实现端点时,框架会在HandleAsync执行完毕后自动检查响应状态:

  • 如果没有通过FastEndpoints提供的SendAsync/SendOkAsync等原生方法发送响应,框架会默认判定没有返回内容,自动将状态码覆盖为204 No Content。
  • 你在自定义扩展方法ToOkOrProblemDetail中直接操作HttpContext.Response写入响应,但未告知FastEndpoints响应已处理完成,因此框架在后续流程中修改了状态码。

解决方案

方案1:使用FastEndpoints原生响应方法(推荐)

替换手动操作HttpContext的方式,改用框架提供的API发送响应,让FastEndpoints正确跟踪响应状态,避免自动修改状态码。

修改端点处理器

public override async Task HandleAsync(CreateAuthorizationRequest request, CancellationToken cancellationToken)
{
    var result = await _mediator.Send(new CreateAuthorizationCommand(request.IdNumber!, action, request.Service!, ""), cancellationToken);

    if (result.IsSuccess)
    {
        var response = new CreateAuthorizationResponse(result.Value.TransactionId, result.Value.Random);
        await SendOkAsync(response); // 框架原生方法,自动设置200状态码并序列化响应
    }
    else
    {
        await SendProblemDetailsAsync(result.ToProblemDetails()); // 用框架方法发送错误响应
    }
}

废弃自定义扩展方法

直接使用FastEndpoints内置方法即可,无需保留ToOkOrProblemDetail扩展方法,状态码会稳定保持为200。


方案2:手动标记响应已处理(保留自定义扩展方法时使用)

如果必须保留自定义扩展方法,需要在写入响应后明确标记响应已开始发送,阻止FastEndpoints修改状态码:

修改扩展方法

public static async Task ToOkOrProblemDetail(this Result result, HttpContext httpContext)
{
    if (result.IsSuccess)
    {
        var responseBody = JsonSerializer.Serialize(result.Value);
        httpContext.Response.StatusCode = StatusCodes.Status200OK;
        httpContext.Response.ContentType = "application/json";
        httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(responseBody);
        await httpContext.Response.WriteAsync(responseBody);
        // 关键:标记响应已开始,FastEndpoints会跳过后续状态码修改逻辑
        httpContext.Response.HasStarted = true;
        Console.WriteLine("Response written with status 200 and content length set");
    }
    else
    {
        await result.ToProblemDetails(httpContext);
        httpContext.Response.HasStarted = true; // 错误响应同样需要标记
    }
}

方案3:修复中间件的响应写入逻辑

你的中间件存在重复写入响应体的问题(同时调用WriteAsync和CopyToAsync),且在状态码变为204后写入会触发异常,修改如下:

public async Task Invoke(HttpContext context)
{
    var requestBody = await GetRequestBody(context.Request);
    var originalBodyStream = context.Response.Body;

    using (var memoryStream = new MemoryStream())
    {
        context.Response.Body = memoryStream;

        Console.WriteLine($"Initial Status Code: {context.Response.StatusCode}");

        await _next(context);

        Console.WriteLine($"Status Code After _next: {context.Response.StatusCode}");

        memoryStream.Seek(0, SeekOrigin.Begin);
        var responseBody = await new StreamReader(memoryStream).ReadToEndAsync();

        // 恢复原始流并直接复制内存流内容,避免重复写入
        context.Response.Body = originalBodyStream;
        if (!string.IsNullOrEmpty(responseBody) && context.Response.StatusCode != StatusCodes.Status204NoContent)
        {
            await memoryStream.CopyToAsync(originalBodyStream);
            context.Response.ContentLength = memoryStream.Length;
        }
    }
}

额外注意:调整中间件位置

确保日志中间件放在FastEndpoints中间件之前,才能正确捕获端点处理的完整流程:

// 调整顺序:先添加日志中间件,再配置FastEndpoints
app.UseMiddleware<RequestLoggingMiddleware>();
app.UseFastEndpoints(x => x.Errors.UseProblemDetails());

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 01:00:17