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

如何修改HttpContext.Response?统一API返回格式实现求助

实现API统一响应格式(成功场景)

一、定义统一响应模型

先创建和需求格式匹配的通用响应模型,和你已有的错误模型保持一致:

// 统一响应模型
public class ResultModel<T>
{
    public T Body { get; set; }
    public ErrorModel Error { get; set; }
}

// 错误模型(和你现有失败逻辑中的模型一致)
public class ErrorModel
{
    public string Message { get; set; }
    public string StatusCode { get; set; }
}

二、方案1:用中间件拦截包装成功响应

通过中间件拦截控制器返回的成功响应,将其包装成统一格式:

1. 实现中间件

public class UnifiedResponseMiddleware
{
    private readonly RequestDelegate _next;
    private readonly JsonSerializerOptions _jsonOptions;

    public UnifiedResponseMiddleware(RequestDelegate next, JsonSerializerOptions jsonOptions)
    {
        _next = next;
        _jsonOptions = jsonOptions;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 保存原始响应流,替换为内存流以便读取响应内容
        var originalResponseBody = context.Response.Body;
        using var newResponseBody = new MemoryStream();
        context.Response.Body = newResponseBody;

        try
        {
            await _next(context);

            // 仅处理2xx状态码的成功响应
            if (context.Response.StatusCode is >= 200 and < 300)
            {
                // 重置内存流指针到起始位置
                newResponseBody.Seek(0, SeekOrigin.Begin);
                var originalContent = await new StreamReader(newResponseBody).ReadToEndAsync();

                // 反序列化原始响应内容
                var originalModel = JsonSerializer.Deserialize<dynamic>(originalContent, _jsonOptions);

                // 包装成统一格式
                var unifiedResult = new ResultModel<dynamic>
                {
                    Body = originalModel,
                    Error = null
                };

                // 重置响应流,写入统一格式内容
                context.Response.Body = originalResponseBody;
                context.Response.ContentType = "application/json";
                await JsonSerializer.SerializeAsync(context.Response.Body, unifiedResult, _jsonOptions);
            }
            else
            {
                // 非成功响应,直接将内存流内容复制回原始响应流
                newResponseBody.Seek(0, SeekOrigin.Begin);
                await newResponseBody.CopyToAsync(originalResponseBody);
            }
        }
        finally
        {
            context.Response.Body = originalResponseBody;
        }
    }
}

// 扩展方法,方便注册中间件
public static class UnifiedResponseMiddlewareExtensions
{
    public static IApplicationBuilder UseUnifiedResponse(this IApplicationBuilder app)
    {
        return app.UseMiddleware<UnifiedResponseMiddleware>();
    }
}

2. 注册中间件

在Program.cs中添加中间件注册,注意顺序要放在路由和端点之间:

var builder = WebApplication.CreateBuilder(args);

// 添加控制器服务
builder.Services.AddControllers();

// 配置Json序列化选项(和你现有代码保持一致,比如驼峰命名)
builder.Services.AddControllers().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});

// 注册Json序列化选项为单例,供中间件使用
builder.Services.AddSingleton(sp => 
    sp.GetRequiredService<IOptions<JsonOptions>>().Value.JsonSerializerOptions);

var app = builder.Build();

app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();

// 注册统一响应中间件
app.UseUnifiedResponse();

app.MapControllers();

app.Run();

三、方案2:用Action过滤器精准处理控制器响应

如果只需要处理控制器的Action结果,用Action过滤器更简洁:

1. 实现过滤器

public class UnifiedResponseFilter : IAsyncResultFilter
{
    private readonly JsonSerializerOptions _jsonOptions;

    public UnifiedResponseFilter(JsonSerializerOptions jsonOptions)
    {
        _jsonOptions = jsonOptions;
    }

    public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        // 仅处理成功的ObjectResult(控制器返回对象时默认生成的结果类型)
        if (context.Result is ObjectResult objectResult && objectResult.StatusCode is >= 200 and < 300)
        {
            // 包装成统一格式,替换原结果
            var unifiedResult = new ResultModel<object>
            {
                Body = objectResult.Value,
                Error = null
            };
            context.Result = new JsonResult(unifiedResult, _jsonOptions);
        }

        await next();
    }
}

2. 注册过滤器

在Program.cs中添加过滤器注册:

builder.Services.AddControllers(options =>
{
    // 添加全局过滤器,对所有控制器生效
    options.Filters.Add<UnifiedResponseFilter>();
});

注意事项

  • 确保Json序列化选项和你现有失败逻辑中的配置一致(比如驼峰命名),避免格式不统一。
  • 如果控制器返回的是ContentResult、FileResult等非对象结果,需要在中间件/过滤器中额外处理。
  • 失败场景你已经实现,上述逻辑仅处理2xx状态码的成功响应,不会覆盖你已有的失败处理逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 11:39:46