Files
QYZH.InteractiveMagazine/QYZH.InteractiveMagazine.Infrastructure/Middleware/GlobalExceptionMiddleware.cs
glz bdaa6a0dc8 refactor: 统一业务异常处理,标准化结果码和错误响应
1.  新增并完善ResultCode枚举,补充标准HTTP状态码对应的业务状态码
2.  重构BusinessException,新增基于ResultCode的构造函数和ThrowIf扩展方法
3.  替换所有硬编码的HTTP状态码为统一的ResultCode枚举
4.  优化全局异常中间件,根据业务状态码映射对应HTTP状态码并规范化JSON响应
5.  修复OssImageHelper和AutoDotCodeConsumer中的OSS文件处理逻辑
6.  新增用户答题快照实体类
7.  清理废弃的宠物模块迁移脚本
2026-06-29 16:34:26 +08:00

111 lines
4.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using System.Text.Json;
namespace QYZH.InteractiveMagazine.Infrastructure.Middleware;
/// <summary>
/// 全局异常中间件
/// </summary>
public class GlobalExceptionMiddleware : IMiddleware
{
private readonly ILogger<GlobalExceptionMiddleware> _logger;
/// <summary>
/// JSON序列化选项camelCase与Controller保持一致
/// </summary>
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
/// <summary>
/// 构造函数
/// </summary>
/// <param name="logger">日志记录器</param>
public GlobalExceptionMiddleware(ILogger<GlobalExceptionMiddleware> logger)
{
_logger = logger;
}
/// <summary>
/// 执行中间件
/// </summary>
/// <param name="context">HTTP上下文</param>
/// <param name="next">下一个中间件委托</param>
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
await next(context);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "业务异常:{Message},状态码:{ResultCode}", ex.Message, ex.ResultCode);
await HandleBusinessExceptionAsync(context, ex);
}
catch (Exception ex)
{
_logger.LogError(ex, "系统异常:{Message}", ex.Message);
await HandleSystemExceptionAsync(context, ex);
}
}
/// <summary>
/// 处理业务异常按业务状态码映射HTTP状态码
/// </summary>
/// <param name="context">HTTP上下文</param>
/// <param name="ex">业务异常</param>
private static async Task HandleBusinessExceptionAsync(HttpContext context, BusinessException ex)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = GetHttpStatusCode(ex.ResultCode);
var response = BaseResponse<object>.Fail(ex.ResultCode, ex.Message);
var json = JsonSerializer.Serialize(response, JsonOptions);
await context.Response.WriteAsync(json);
}
/// <summary>
/// 处理系统异常
/// </summary>
/// <param name="context">HTTP上下文</param>
/// <param name="ex">系统异常</param>
private static async Task HandleSystemExceptionAsync(HttpContext context, Exception ex)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
var response = BaseResponse<object>.Fail(ResultCode.GLOBAL_ERROR, "系统内部错误,请稍后重试");
var json = JsonSerializer.Serialize(response, JsonOptions);
await context.Response.WriteAsync(json);
}
/// <summary>
/// 根据业务状态码获取对应的HTTP状态码
/// </summary>
/// <param name="resultCode">业务状态码</param>
/// <returns>HTTP状态码</returns>
private static int GetHttpStatusCode(ResultCode resultCode)
{
return resultCode switch
{
ResultCode.DENY => StatusCodes.Status401Unauthorized,
ResultCode.FORBIDDEN => StatusCodes.Status403Forbidden,
ResultCode.NOT_FOUND => StatusCodes.Status404NotFound,
ResultCode.BAD_REQUEST => StatusCodes.Status400BadRequest,
ResultCode.PARAM_ERROR => StatusCodes.Status400BadRequest,
ResultCode.CONFLICT => StatusCodes.Status409Conflict,
ResultCode.UNPROCESSABLE_ENTITY => StatusCodes.Status422UnprocessableEntity,
ResultCode.TOO_MANY_REQUESTS => StatusCodes.Status429TooManyRequests,
ResultCode.BAD_GATEWAY => StatusCodes.Status502BadGateway,
ResultCode.SERVICE_UNAVAILABLE => StatusCodes.Status503ServiceUnavailable,
_ => StatusCodes.Status400BadRequest
};
}
}