Skip to content
bitzorcas
EN

Concept

错误处理

全局错误处理 — 通过 GlobalExceptionHandler 实现 RFC 9457 ProblemDetails,Result\<T\> 领域错误模式和结构化错误响应。

Last updated

BitzOrcas 使用双错误处理策略Result<T> 用于领域级失败,GlobalExceptionHandler 用于 HTTP 边界的 RFC 9457 ProblemDetails 转换。

Result<T> 模式

领域服务返回 Result<T> 而非抛出异常:

public Result<Note> CreateNote(string title, string content)
{
if (string.IsNullOrWhiteSpace(title))
return Result<Note>.Failure(Error.Validation("Note.Title", "标题不能为空"));
if (content.Length > 10000)
return Result<Note>.Failure(Error.Validation("Note.Content", "内容过长"));
var note = new Note(title, content);
return Result<Note>.Success(note);
}

错误类型

public enum ErrorType
{
Validation, // 400 — 输入验证失败
NotFound, // 404 — 资源未找到
Conflict, // 409 — 重复/乐观并发冲突
Unauthorized, // 401 — 需要认证
Forbidden, // 403 — 权限不足
Failure, // 500 — 领域/业务规则失败
Infrastructure // 503 — 外部依赖失败
}

错误结构

public readonly record struct Error
{
public ErrorType Type { get; }
public string Code { get; } // 例如 "Note.NotFound"
public string Description { get; }
}

GlobalExceptionHandler

在 HTTP 边界捕获未处理异常并转换为 ProblemDetails:

public class GlobalExceptionHandler : IExceptionHandler
{
public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
// 将异常类型映射到 ProblemDetails
}
}

ProblemDetails 响应格式

所有错误响应遵循带 BitzOrcas 扩展的 RFC 9457:

{
"type": "https://docs.bitzsoft.com/problems/not-found",
"title": "Not Found",
"status": 404,
"detail": "Note with ID 'abc123' was not found.",
"instance": "/api/notes/abc123",
"traceId": "00-abc123def456-...",
"correlationId": "corr-789",
"requestId": "req-012",
"errorCode": "Note.NotFound"
}

标准扩展

扩展来源描述
traceIdActivity.Current分布式跟踪标识符
correlationIdCorrelationIdMiddleware请求关联 ID
requestIdHttpContext每请求标识符
errorCodeError.Code机器可读错误码
retryAfter限流器允许重试前的秒数(仅 429)

Result 到 HTTP 的转换

在 Minimal API 端点中:

app.MapPost("/api/notes", async (
CreateNoteCommand cmd, IMediator mediator) =>
{
var result = await mediator.Send(cmd);
return result.Match(
onSuccess: value => Results.Created($"/api/notes/{value.Id}", value),
onFailure: error => error.ToProblemDetails()
);
});

验证错误

ValidationPipelineBehavior 捕获 IRequestRule 失败并返回结构化验证错误:

{
"type": "https://docs.bitzsoft.com/problems/validation",
"title": "Validation Failed",
"status": 400,
"errors": {
"Title": ["Title is required"],
"Content": ["Content must not exceed 10000 characters"]
}
}

限流错误(429)

{
"type": "https://docs.bitzsoft.com/problems/rate-limit-exceeded",
"title": "Too Many Requests",
"status": 429,
"detail": "Rate limit exceeded.",
"retryAfter": 60,
"traceId": "...",
"correlationId": "...",
"errorCode": "RateLimit.Exceeded"
}