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

.NET 7 Web API全局统一BaseResponse格式响应实现问询

.NET 7 REST API 全场景统一响应格式实现方案

先明确统一响应模型的基础定义(示例):

public class ResponseBase<T>
{
    public bool Success { get; set; }
    public T? Data { get; set; }
    public string? Message { get; set; }
    public int StatusCode { get; set; }

    public static ResponseBase<T> SuccessResult(T data, int statusCode = 200)
    {
        return new ResponseBase<T> { Success = true, Data = data, StatusCode = statusCode };
    }

    public static ResponseBase<T> FailResult(string message, int statusCode)
    {
        return new ResponseBase<T> { Success = false, Message = message, StatusCode = statusCode };
    }
}

// 无数据场景的简化版本
public class ResponseBase : ResponseBase<object>
{
    public static new ResponseBase FailResult(string message, int statusCode)
    {
        return new ResponseBase { Success = false, Message = message, StatusCode = statusCode };
    }
}

一、自定义全局响应中间件

覆盖路由不存在、未授权、服务器异常等全局场景,捕获并包装成统一格式:

public class GlobalResponseMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<GlobalResponseMiddleware> _logger;

    public GlobalResponseMiddleware(RequestDelegate next, ILogger<GlobalResponseMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);

            // 处理非200状态码的响应
            if (context.Response.StatusCode != StatusCodes.Status200OK)
            {
                await HandleStatusCodeResponse(context);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "未处理的服务器异常");
            await HandleExceptionResponse(context, ex);
        }
    }

    private async Task HandleStatusCodeResponse(HttpContext context)
    {
        context.Response.ContentType = "application/json";
        var response = context.Response;

        ResponseBase result;
        switch (response.StatusCode)
        {
            case StatusCodes.Status401Unauthorized:
                result = ResponseBase.FailResult("未授权访问", StatusCodes.Status401Unauthorized);
                break;
            case StatusCodes.Status403Forbidden:
                result = ResponseBase.FailResult("无权限访问", StatusCodes.Status403Forbidden);
                break;
            case StatusCodes.Status404NotFound:
                result = ResponseBase.FailResult("请求资源不存在", StatusCodes.Status404NotFound);
                break;
            case StatusCodes.Status400BadRequest:
                result = ResponseBase.FailResult("请求参数错误", StatusCodes.Status400BadRequest);
                break;
            default:
                result = ResponseBase.FailResult($"服务器错误,状态码:{response.StatusCode}", response.StatusCode);
                break;
        }

        await context.Response.WriteAsJsonAsync(result);
    }

    private async Task HandleExceptionResponse(HttpContext context, Exception ex)
    {
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;

        var result = ResponseBase.FailResult("服务器内部异常", StatusCodes.Status500InternalServerError);
        // 开发环境可显示异常详情,生产环境关闭
        if (context.RequestServices.GetRequiredService<IWebHostEnvironment>().IsDevelopment())
        {
            result.Message += $":{ex.Message}";
        }

        await context.Response.WriteAsJsonAsync(result);
    }
}

在Program.cs中注册中间件(注意顺序:放在UseRouting之后,UseAuthorization之前):

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

// 注册全局响应中间件
app.UseMiddleware<GlobalResponseMiddleware>();

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

app.MapControllers();

app.Run();

二、动作过滤器覆盖控制器内置结果

处理控制器直接返回的NotFound()、Unauthorized()等内置结果,强制包装成统一格式:

public class ResponseWrapFilter : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var resultContext = await next();

        // 已为统一格式则跳过
        if (resultContext.Result is ObjectResult objResult && objResult.Value is ResponseBase)
        {
            return;
        }

        ResponseBase response;
        switch (resultContext.Result)
        {
            case NotFoundResult:
                response = ResponseBase.FailResult("请求资源不存在", StatusCodes.Status404NotFound);
                break;
            case UnauthorizedResult:
                response = ResponseBase.FailResult("未授权访问", StatusCodes.Status401Unauthorized);
                break;
            case ForbidResult:
                response = ResponseBase.FailResult("无权限访问", StatusCodes.Status403Forbidden);
                break;
            case BadRequestResult:
                response = ResponseBase.FailResult("请求参数错误", StatusCodes.Status400BadRequest);
                break;
            case ObjectResult objectResult:
                // 正常响应包装为成功结果
                response = ResponseBase.SuccessResult(objectResult.Value, objectResult.StatusCode ?? StatusCodes.Status200OK);
                break;
            default:
                response = ResponseBase.SuccessResult(null, StatusCodes.Status200OK);
                break;
        }

        resultContext.Result = new ObjectResult(response)
        {
            StatusCode = response.StatusCode
        };
    }
}

在Program.cs中注册全局过滤器:

builder.Services.AddControllers(options =>
{
    options.Filters.Add<ResponseWrapFilter>();
});

三、验证覆盖场景

  • 控制器返回NotFound():过滤器直接包装为统一格式
  • 路由不存在:中间件捕获404状态码返回统一格式
  • 未授权/无权限:中间件捕获401/403状态码返回统一格式
  • 服务器异常:中间件捕获异常返回统一格式
  • 正常业务响应:过滤器自动包装为成功结果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 09:53:21