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

.NET 7中如何统一错误响应的问题详情格式?

统一.NET 7中NotFound响应格式的方案

方法一:自定义ProblemDetailsFactory(全局统一所有错误响应)

ASP.NET Core 默认通过 ProblemDetailsFactory 生成标准化错误响应,重写这个类可以全局统一所有错误的输出格式,包括NotFound:

  1. 创建自定义工厂类,继承默认的ProblemDetailsFactory:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Options;
using System.Diagnostics;

public class CustomProblemDetailsFactory : ProblemDetailsFactory
{
    private readonly ApiBehaviorOptions _apiOptions;

    public CustomProblemDetailsFactory(IOptions<ApiBehaviorOptions> apiOptions)
    {
        _apiOptions = apiOptions?.Value ?? throw new ArgumentNullException(nameof(apiOptions));
    }

    public override ProblemDetails CreateProblemDetails(
        HttpContext httpContext,
        int? statusCode = null,
        string? title = null,
        string? type = null,
        string? detail = null,
        string? instance = null)
    {
        statusCode ??= 500;

        var problemDetails = new ProblemDetails
        {
            Status = statusCode,
            Title = title ?? _apiOptions.ClientErrorMapping[statusCode].Title,
            Type = type ?? _apiOptions.ClientErrorMapping[statusCode].Link,
            Detail = detail,
            Instance = instance
        };

        AddCommonExtensions(httpContext, problemDetails, statusCode.Value);
        return problemDetails;
    }

    public override ValidationProblemDetails CreateValidationProblemDetails(
        HttpContext httpContext,
        ModelStateDictionary modelStateDictionary,
        int? statusCode = null,
        string? title = null,
        string? type = null,
        string? detail = null,
        string? instance = null)
    {
        if (modelStateDictionary == null)
            throw new ArgumentNullException(nameof(modelStateDictionary));

        statusCode ??= 400;

        var problemDetails = new ValidationProblemDetails(modelStateDictionary)
        {
            Status = statusCode,
            Type = type ?? _apiOptions.ClientErrorMapping[statusCode].Link,
            Detail = detail,
            Instance = instance
        };

        if (title != null)
            problemDetails.Title = title;

        AddCommonExtensions(httpContext, problemDetails, statusCode.Value);
        return problemDetails;
    }

    private void AddCommonExtensions(HttpContext httpContext, ProblemDetails problemDetails, int statusCode)
    {
        problemDetails.Status ??= statusCode;

        if (_apiOptions.ClientErrorMapping.TryGetValue(statusCode, out var errorData))
        {
            problemDetails.Title ??= errorData.Title;
            problemDetails.Type ??= errorData.Link;
        }

        // 添加TraceId便于排查问题
        var traceId = Activity.Current?.Id ?? httpContext?.TraceIdentifier;
        if (traceId != null)
            problemDetails.Extensions["traceId"] = traceId;

        // 针对404场景,确保无传入消息时也有默认detail
        if (problemDetails.Status == 404 && string.IsNullOrEmpty(problemDetails.Detail))
            problemDetails.Detail = "请求的资源未找到";
    }
}
  1. 在Program.cs中替换默认的工厂实现:
builder.Services.AddSingleton<ProblemDetailsFactory, CustomProblemDetailsFactory>();

之后不管调用return NotFound()还是return NotFound("用户不存在"),都会返回结构完全一致的响应:

无消息时的响应:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  "title": "Not Found",
  "status": 404,
  "detail": "请求的资源未找到",
  "traceId": "00-xxxxxxxxx-xxxxxxxxx-00"
}

带自定义消息时的响应:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  "title": "Not Found",
  "status": 404,
  "detail": "用户不存在",
  "traceId": "00-xxxxxxxxx-xxxxxxxxx-00"
}

方法二:自定义UnifiedNotFoundResult(仅针对NotFound场景)

如果只需要统一NotFound的格式,不想影响其他错误响应,可以自定义一个专属的ActionResult:

  1. 创建自定义结果类:
using Microsoft.AspNetCore.Mvc;

public class UnifiedNotFoundResult : ObjectResult
{
    public UnifiedNotFoundResult(string? message = null) 
        : base(new ProblemDetails
        {
            Status = StatusCodes.Status404NotFound,
            Title = "资源不存在",
            Type = "https://your-docs.com/errors/404",
            Detail = message ?? "请求的资源未找到"
        })
    {
        StatusCode = StatusCodes.Status404NotFound;
    }
}
  1. 在控制器中直接使用:
// 无自定义消息
return new UnifiedNotFoundResult();
// 带自定义消息
return new UnifiedNotFoundResult("指定的商品不存在");

这种方式更轻量化,仅作用于NotFound场景,适合不需要全局统一所有错误格式的场景。

方法三:配置ApiBehaviorOptions(简单统一标题和类型)

如果只需要统一NotFound的标题和类型,不需要修改detail的逻辑,可以直接配置ApiBehaviorOptions:

builder.Services.Configure<ApiBehaviorOptions>(options =>
{
    options.ClientErrorMapping[StatusCodes.Status404NotFound] = new ClientErrorData
    {
        Title = "资源不存在",
        Link = "https://your-docs.com/errors/404"
    };
});

这种方式只能调整默认的标题和类型链接,无法统一detail的存在性,适合需求简单的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 18:12:44