exception

package
v0.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2026 License: MIT Imports: 11 Imported by: 0

README

exception 包 — 异常处理

所属层级: Infrastructure Layer
设计理念: 全局异常处理,统一错误码
设计灵感: Spring @ControllerAdvice + Spring Error Handling

概述

exception 包提供统一的应用层异常处理机制,实现类似 Spring Boot @ControllerAdvice 的全局异常处理功能。

核心功能
功能 说明
全局异常处理 统一的异常捕获和响应机制
自定义异常映射 自定义异常到 HTTP 响应的映射
异常解析器链 优先级排序的异常解析器链
HTTP 中间件 自动捕获 HTTP 请求中的异常
日志和监控集成 与日志和监控系统无缝集成
安全模块适配 AccessDeniedHandler 和 AuthenticationEntryPoint 适配器
统一错误码体系 业务错误码定义、注册和解析

核心接口

ExceptionHandler 异常处理器
type ExceptionHandler interface {
    Handle(ctx context.Context, err error, response ResponseWriter) *ErrorResponse
    RegisterResolver(resolver ExceptionResolver)
    RegisterHandlerFunc(handlerFunc ExceptionHandlerFunc)
}
ExceptionResolver 异常解析器
type ExceptionResolver interface {
    Supports(err error) bool
    Resolve(ctx context.Context, err error) *ErrorResponse
}
ErrorCode 业务错误码
type ErrorCode struct {
    Code    int    // HTTP 状态码
    Message string // 用户可见消息
    Detail  string // 开发者调试信息
}
BusinessError 业务错误包装器
type BusinessError struct {
    code    ErrorCode
    details map[string]any
}

快速开始

基本异常处理
package main

import (
    "context"
    "github.com/xudefa/enhance/exception"
)

func main() {
    handler := exception.NewDefaultExceptionHandler()
    resp := handler.Handle(context.Background(), exception.ErrNotFound, response)
}

API 参考

HTTP 中间件
handler := exception.NewDefaultExceptionHandler()
middleware := exception.ExceptionHandlingMiddleware(handler)
http.Handle("/", middleware(httpHandler))
自定义异常解析器
type CustomExceptionResolver struct{}

func (r *CustomExceptionResolver) Supports(err error) bool {
    _, ok := err.(*CustomException)
    return ok
}

func (r *CustomExceptionResolver) Resolve(ctx context.Context, err error) *exception.ErrorResponse {
    return exception.NewErrorResponse().
        WithCode(400).
        WithMessage("Custom error").
        WithDetails(err.Error())
}

handler.RegisterResolver(&CustomExceptionResolver{})
业务错误码
// 定义业务错误码
var ErrUserNotFound = exception.ErrorCode{
    Code:    404,
    Message: "用户不存在",
    Detail:  "user_not_found",
}

// 注册错误码
exception.RegisterErrorCode(ErrUserNotFound)

// 使用业务错误
err := exception.New(ErrUserNotFound).
    WithDetail("id", "123").
    WithDetail("type", "user")
与 ErrorCodeExceptionResolver 集成
resolver := exception.NewErrorCodeExceptionResolver()
response := resolver.Resolve(ctx, err)
// response.Code == 404
// response.Message == "用户不存在"

预定义错误码

错误码 HTTP 状态码 消息 详情
ErrCodeBadRequest 400 请求参数错误 bad_request
ErrCodeUnauthorized 401 未授权 unauthorized
ErrCodeForbidden 403 禁止访问 forbidden
ErrCodeNotFound 404 资源不存在 not_found
ErrCodeMethodNotAllowed 405 方法不允许 method_not_allowed
ErrCodeConflict 409 资源冲突 conflict
ErrCodeInternalServerError 500 服务器内部错误 internal_server_error
ErrCodeServiceUnavailable 503 服务不可用 service_unavailable

错误响应格式

{
    "code": 404,
    "message": "用户不存在",
    "requestId": "req-123",
    "traceId": "trace-456",
    "details": "user_not_found",
    "timestamp": 1640995200
}

使用示例

Web 全局异常处理
func main() {
    handler := exception.NewDefaultExceptionHandler()
    
    // 注册自定义解析器
    handler.RegisterResolver(&validationExceptionResolver{})
    handler.RegisterResolver(&businessExceptionResolver{})
    
    // 创建中间件
    middleware := exception.ExceptionHandlingMiddleware(handler)
    
    // 应用到路由
    mux := http.NewServeMux()
    mux.HandleFunc("/api/users", usersHandler)
    
    http.ListenAndServe(":8080", middleware(mux))
}
业务异常处理
type UserService struct{}

func (s *UserService) GetUser(id string) (*User, error) {
    user, err := s.findUser(id)
    if err != nil {
        return nil, exception.New(exception.ErrUserNotFound).
            WithDetail("id", id).
            WithDetail("type", "user")
    }
    return user, nil
}
验证异常解析器
type validationExceptionResolver struct{}

func (r *validationExceptionResolver) Supports(err error) bool {
    _, ok := err.(*validation.ValidationException)
    return ok
}

func (r *validationExceptionResolver) Resolve(ctx context.Context, err error) *exception.ErrorResponse {
    ve := err.(*validation.ValidationException)
    return exception.NewErrorResponse().
        WithCode(400).
        WithMessage("Validation failed").
        WithDetails(ve.Errors)
}

最佳实践

1. 使用统一错误码体系
// ✅ 推荐:定义业务错误码
var (
    ErrUserNotFound = exception.ErrorCode{
        Code:    404,
        Message: "用户不存在",
        Detail:  "user_not_found",
    }
    ErrUserAlreadyExists = exception.ErrorCode{
        Code:    409,
        Message: "用户已存在",
        Detail:  "user_already_exists",
    }
)

// ⚠️ 不推荐:硬编码错误响应
func handler(w http.ResponseWriter, r *http.Request) {
    http.Error(w, "User not found", 404)
}
2. 使用中间件统一捕获异常
// ✅ 推荐:使用中间件统一处理
handler := exception.NewDefaultExceptionHandler()
middleware := exception.ExceptionHandlingMiddleware(handler)
http.ListenAndServe(":8080", middleware(mux))

// ⚠️ 不推荐:每个处理器重复捕获逻辑
func handler(w http.ResponseWriter, r *http.Request) {
    defer func() {
        if err := recover(); err != nil {
            // 手动处理异常
        }
    }()
}
3. 注册自定义异常解析器
// ✅ 推荐:按优先级注册解析器
handler.RegisterResolver(&validationExceptionResolver{})
handler.RegisterResolver(&businessExceptionResolver{})
handler.RegisterResolver(&defaultExceptionResolver{})

// ⚠️ 不推荐:不注册解析器,使用默认处理
handler := exception.NewDefaultExceptionHandler()
4. 使用 BusinessError 包装业务异常
// ✅ 推荐:使用 BusinessError 包装
err := exception.New(exception.ErrUserNotFound).
    WithDetail("id", id).
    WithDetail("type", "user")

// ⚠️ 不推荐:直接返回普通错误
err := fmt.Errorf("user not found: %s", id)
5. 与日志和监控集成
// ✅ 推荐:记录异常日志
func (h *ExceptionHandler) Handle(ctx context.Context, err error, response ResponseWriter) *ErrorResponse {
    resp := h.resolveError(ctx, err)
    
    // 记录日志
    if resp.Code >= 500 {
        log.Error(ctx, "Internal server error", 
            log.KeyValue{Key: "error", Value: err.Error()},
            log.KeyValue{Key: "code", Value: resp.Code},
        )
    }
    
    // 上报监控指标
    metrics.IncrementCounter("http_errors", "code", strconv.Itoa(resp.Code))
    
    return resp
}
6. 设计原则
  • 参考 Spring @ControllerAdvice:借鉴 Spring 的全局异常处理设计理念
  • 统一错误响应:所有异常都转换为统一的错误响应格式
  • 可扩展:支持自定义异常解析器和处理函数
  • 优先级链:支持多个解析器按优先级处理异常
  • 零外部依赖:核心框架仅使用 Go 标准库

Documentation

Overview

Package exception 提供异常处理和错误响应功能,用于 enhance 框架。

该模块提供统一的异常处理机制,包括错误响应格式、错误码管理、异常处理器等。 参考 Spring 的 @ExceptionHandler 设计。

架构设计

  • ExceptionHandler: 异常处理器接口,核心异常处理入口
  • ExceptionResolver: 异常解析器接口,解析异常并生成统一错误响应
  • Logger: 日志接口,抽象层不依赖具体日志实现
  • MetricsRecorder: 指标记录器接口,用于记录异常指标到监控系统
  • ResponseWriter: 响应写入器接口,适配不同 HTTP 框架的响应写入
  • ErrorCode: 业务错误码,包含 HTTP 状态码、用户可见消息和开发者调试信息
  • ErrorResponse: 统一错误响应格式

核心功能

  • 统一错误响应: 提供标准化的错误响应格式
  • 错误码管理: 支持业务错误码定义和管理
  • 异常处理: 支持全局异常捕获和处理
  • 错误日志: 自动记录错误日志
  • 安全过滤: 过滤敏感信息,防止信息泄露

使用方式

定义错误码:

var (
    ErrUserNotFound     = exception.ErrorCode{404, "用户不存在", "user_not_found"}
    ErrInvalidParameter = exception.ErrorCode{400, "参数错误", "invalid_parameter"}
)

创建错误响应:

resp := exception.NewErrorResponse(404, "用户不存在", "", "", nil)

注册异常处理器:

handler := exception.NewExceptionHandler(config)
handler.RegisterResolver(resolver)

错误响应格式

{
  "code": 404,
  "message": "用户不存在",
  "requestId": "req-123",
  "traceId": "trace-456",
  "details": {...},
  "timestamp": 1704067200000
}

Package exception 提供异常处理和错误响应功能,用于 enhance 框架。

Package exception 提供异常处理和错误响应功能,用于 enhance 框架。

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrNotFound       = errors.New("resource not found")
	ErrBadRequest     = errors.New("bad request")
	ErrUnauthorized   = errors.New("unauthorized access")
	ErrForbidden      = errors.New("forbidden")
	ErrConflict       = errors.New("resource conflict")
	ErrInternalServer = errors.New("internal server error")
)
View Source
var (
	ErrCodeBadRequest          = ErrorCode{400, "请求参数错误", "bad_request"}
	ErrCodeUnauthorized        = ErrorCode{401, "未授权", "unauthorized"}
	ErrCodeForbidden           = ErrorCode{403, "禁止访问", "forbidden"}
	ErrCodeNotFound            = ErrorCode{404, "资源不存在", "not_found"}
	ErrCodeMethodNotAllowed    = ErrorCode{405, "方法不允许", "method_not_allowed"}
	ErrCodeConflict            = ErrorCode{409, "资源冲突", "conflict"}
	ErrCodeInternalServerError = ErrorCode{500, "服务器内部错误", "internal_server_error"}
	ErrCodeServiceUnavailable  = ErrorCode{503, "服务不可用", "service_unavailable"}
)

预定义的业务错误码(不与其他包冲突)

Functions

func ExceptionHandlingMiddleware

func ExceptionHandlingMiddleware(handler ExceptionHandler) func(http.Handler) http.Handler

ExceptionHandlingMiddleware HTTP 异常处理中间件

ExceptionHandlingMiddleware 是一个 HTTP 中间件,用于自动捕获和处理 HTTP 处理过程中的异常。 它会捕获 panic 和返回的异常,并通过 ExceptionHandler 处理它们。

使用示例:

handler := exception.NewDefaultExceptionHandler()
middleware := exception.ExceptionHandlingMiddleware(handler)
http.Handle("/", middleware(httpHandler))
Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/xudefa/enhance/exception"
)

func main() {
	handler := exception.NewDefaultExceptionHandler()
	middleware := exception.ExceptionHandlingMiddleware(handler)

	httpHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/panic" {
			panic("something went wrong")
		}
		w.WriteHeader(http.StatusOK)
		_, _ = w.Write([]byte("OK"))
	})

	wrappedHandler := middleware(httpHandler)

	req := httptest.NewRequest("GET", "/panic", nil)
	w := httptest.NewRecorder()

	wrappedHandler.ServeHTTP(w, req)

	fmt.Printf("Status: %d\n", w.Code)

}

func RegisterErrorCode

func RegisterErrorCode(code ErrorCode)

RegisterErrorCode 注册错误码到全局注册表

Types

type AccessDeniedHandlerAdapter

type AccessDeniedHandlerAdapter struct {
	// contains filtered or unexported fields
}

AccessDeniedHandlerAdapter 适配 AccessDeniedHandler 到异常处理器

AccessDeniedHandlerAdapter 是一个适配器,将安全模块的 AccessDeniedHandler 接口适配到异常处理器。 这样可以将访问拒绝异常统一通过异常处理器处理,实现一致的错误响应格式。

Example
package main

import (
	"context"
	"fmt"

	"github.com/xudefa/enhance/exception"
)

func main() {
	handler := exception.NewDefaultExceptionHandler()
	adapter := exception.NewAccessDeniedHandlerAdapter(handler)

	response := &mockResponseWriter{}
	adapter.Handle(response, exception.ErrForbidden)

	fmt.Printf("Status: %d\n", response.statusCode)

}

type mockResponseWriter struct {
	statusCode int
	headers    map[string]string
	body       []byte
}

func (m *mockResponseWriter) SetStatusCode(code int) {
	m.statusCode = code
}

func (m *mockResponseWriter) SetHeader(key, value string) {
	if m.headers == nil {
		m.headers = make(map[string]string)
	}
	m.headers[key] = value
}

func (m *mockResponseWriter) Write(data []byte) error {
	m.body = data
	return nil
}

func (m *mockResponseWriter) Context() context.Context {
	return context.Background()
}

func NewAccessDeniedHandlerAdapter

func NewAccessDeniedHandlerAdapter(handler ExceptionHandler) *AccessDeniedHandlerAdapter

NewAccessDeniedHandlerAdapter 创建 AccessDeniedHandler 适配器

返回一个 AccessDeniedHandlerAdapter 实例,该实例会使用提供的异常处理器处理异常。

func (*AccessDeniedHandlerAdapter) Handle

func (a *AccessDeniedHandlerAdapter) Handle(response ResponseWriter, err error)

Handle 处理访问拒绝异常

当访问被拒绝时,调用此方法处理异常。 如果异常不为 nil,会通过异常处理器处理,并将响应写入 ResponseWriter。

type AuthenticationEntryPointAdapter

type AuthenticationEntryPointAdapter struct {
	// contains filtered or unexported fields
}

AuthenticationEntryPointAdapter 适配 AuthenticationEntryPoint 到异常处理器

AuthenticationEntryPointAdapter 是一个适配器,将安全模块的 AuthenticationEntryPoint 接口适配到异常处理器。 这样可以将认证入口点异常统一通过异常处理器处理,实现一致的错误响应格式。

Example
package main

import (
	"context"
	"fmt"

	"github.com/xudefa/enhance/exception"
)

func main() {
	handler := exception.NewDefaultExceptionHandler()
	adapter := exception.NewAuthenticationEntryPointAdapter(handler)

	response := &mockResponseWriter{}
	adapter.Commence(response, exception.ErrUnauthorized)

	fmt.Printf("Status: %d\n", response.statusCode)

}

type mockResponseWriter struct {
	statusCode int
	headers    map[string]string
	body       []byte
}

func (m *mockResponseWriter) SetStatusCode(code int) {
	m.statusCode = code
}

func (m *mockResponseWriter) SetHeader(key, value string) {
	if m.headers == nil {
		m.headers = make(map[string]string)
	}
	m.headers[key] = value
}

func (m *mockResponseWriter) Write(data []byte) error {
	m.body = data
	return nil
}

func (m *mockResponseWriter) Context() context.Context {
	return context.Background()
}

func NewAuthenticationEntryPointAdapter

func NewAuthenticationEntryPointAdapter(handler ExceptionHandler) *AuthenticationEntryPointAdapter

NewAuthenticationEntryPointAdapter 创建 AuthenticationEntryPoint 适配器

返回一个 AuthenticationEntryPointAdapter 实例,该实例会使用提供的异常处理器处理异常。

func (*AuthenticationEntryPointAdapter) Commence

func (a *AuthenticationEntryPointAdapter) Commence(response ResponseWriter, err error)

Commence 处理认证入口点异常

当认证失败时,调用此方法处理异常。 如果异常不为 nil,会通过异常处理器处理,并将响应写入 ResponseWriter。

type BuiltinExceptionResolver

type BuiltinExceptionResolver struct{}

BuiltinExceptionResolver 内置异常解析器

BuiltinExceptionResolver 处理包中定义的内置异常类型: - ErrNotFound → 404 - ErrBadRequest → 400 - ErrUnauthorized → 401 - ErrForbidden → 403 - ErrConflict → 409 - ErrInternalServer → 500

func (*BuiltinExceptionResolver) Order

func (r *BuiltinExceptionResolver) Order() int

Order 中等优先级

返回 100,高于默认解析器,低于自定义解析器。

func (*BuiltinExceptionResolver) Resolve

Resolve 根据异常类型返回对应响应

根据异常类型返回相应的 HTTP 状态码和错误消息。

func (*BuiltinExceptionResolver) Supports

func (r *BuiltinExceptionResolver) Supports(err error) bool

Supports 支持内置异常

检查异常是否是包中定义的内置异常之一。

type BusinessError

type BusinessError struct {
	// contains filtered or unexported fields
}

BusinessError 业务错误

包装 ErrorCode 并支持附加详细信息。

func New

func New(code ErrorCode) *BusinessError

New 创建业务错误

func (*BusinessError) Error

func (e *BusinessError) Error() string

Error 实现 error 接口

func (*BusinessError) ErrorCode

func (e *BusinessError) ErrorCode() ErrorCode

ErrorCode 返回错误码

func (*BusinessError) GetDetails

func (e *BusinessError) GetDetails() map[string]any

GetDetails 获取详细信息

func (*BusinessError) WithDetail

func (e *BusinessError) WithDetail(key string, value any) *BusinessError

WithDetail 添加详细信息

func (*BusinessError) WithDetails

func (e *BusinessError) WithDetails(details map[string]any) *BusinessError

WithDetails 批量添加详细信息

type DefaultExceptionHandler

type DefaultExceptionHandler struct {
	// contains filtered or unexported fields
}

DefaultExceptionHandler 默认异常处理器实现。

DefaultExceptionHandler 是 ExceptionHandler 接口的主要实现,提供了完整的异常处理功能: - 使用解析器链处理不同类型的异常 - 支持日志和监控集成 - 自动写入 HTTP 响应 - 支持基于类型的异常处理函数注册

Example
package main

import (
	"context"
	"fmt"

	"github.com/xudefa/enhance/exception"
)

func main() {
	handler := exception.NewDefaultExceptionHandler()

	response := &mockResponseWriter{}
	resp := handler.Handle(context.Background(), exception.ErrNotFound, response)

	fmt.Printf("Code: %d, Message: %s\n", resp.Code, resp.Message)

}

type mockResponseWriter struct {
	statusCode int
	headers    map[string]string
	body       []byte
}

func (m *mockResponseWriter) SetStatusCode(code int) {
	m.statusCode = code
}

func (m *mockResponseWriter) SetHeader(key, value string) {
	if m.headers == nil {
		m.headers = make(map[string]string)
	}
	m.headers[key] = value
}

func (m *mockResponseWriter) Write(data []byte) error {
	m.body = data
	return nil
}

func (m *mockResponseWriter) Context() context.Context {
	return context.Background()
}
Example (WithOptions)
package main

import (
	"context"
	"fmt"

	"github.com/xudefa/enhance/exception"
)

func main() {
	metrics := exception.NewDefaultMetricsRecorder()

	handler := exception.NewDefaultExceptionHandler(
		exception.WithMetricsRecorder(metrics),
	)

	response := &mockResponseWriter{}
	resp := handler.Handle(context.Background(), exception.ErrBadRequest, response)

	fmt.Printf("Code: %d, Message: %s\n", resp.Code, resp.Message)

}

type mockResponseWriter struct {
	statusCode int
	headers    map[string]string
	body       []byte
}

func (m *mockResponseWriter) SetStatusCode(code int) {
	m.statusCode = code
}

func (m *mockResponseWriter) SetHeader(key, value string) {
	if m.headers == nil {
		m.headers = make(map[string]string)
	}
	m.headers[key] = value
}

func (m *mockResponseWriter) Write(data []byte) error {
	m.body = data
	return nil
}

func (m *mockResponseWriter) Context() context.Context {
	return context.Background()
}

func (*DefaultExceptionHandler) Handle

Handle 处理异常。

Handle 方法是异常处理的核心方法,它会: 1. 检查异常是否为 nil 2. 查找类型匹配的处理函数 3. 使用解析器链查找合适的解析器 4. 如果没有找到解析器,返回 500 错误 5. 将响应写入 ResponseWriter 6. 记录日志和指标(如果配置)

func (*DefaultExceptionHandler) IncludeStackTrace added in v0.0.4

func (h *DefaultExceptionHandler) IncludeStackTrace() bool

IncludeStackTrace 返回是否在错误响应中包含堆栈跟踪信息。

供 ExceptionHandlingMiddleware 判断 panic 恢复时是否附加堆栈跟踪, 生产环境默认关闭,避免泄露源码路径等敏感信息。

func (*DefaultExceptionHandler) RegisterException

func (h *DefaultExceptionHandler) RegisterException(exceptionType reflect.Type, resolver ExceptionResolver)

RegisterException 注册异常类型和解析器。

为特定异常类型注册专用解析器,与 RegisterHandlerFunc 等效: 注册后该异常类型及其包装错误会优先生成响应,而非加入解析器链。

func (*DefaultExceptionHandler) RegisterHandlerFunc

func (h *DefaultExceptionHandler) RegisterHandlerFunc(exceptionType reflect.Type, handler func(ctx context.Context, err error) *ErrorResponse)

RegisterHandlerFunc 注册异常类型和处理函数。

为特定异常类型注册处理函数,该函数会优先于解析器链执行。 这是一种更直接、更高效的异常处理方式。

func (*DefaultExceptionHandler) RegisterResolver

func (h *DefaultExceptionHandler) RegisterResolver(resolver ExceptionResolver)

RegisterResolver 注册解析器。

将自定义解析器添加到解析器链中,解析器会自动按 Order 排序。 优先级数值越小,优先级越高。

type DefaultExceptionResolver

type DefaultExceptionResolver struct{}

DefaultExceptionResolver 默认异常解析器(兜底)

DefaultExceptionResolver 是一个兜底解析器,支持所有异常类型。 它总是返回 500 错误,优先级最低(Order = 1000),确保在没有其他解析器匹配时也能返回响应。

func (*DefaultExceptionResolver) Order

func (r *DefaultExceptionResolver) Order() int

Order 最低优先级

返回 1000,确保在其他解析器都不匹配时才使用这个解析器。

func (*DefaultExceptionResolver) Resolve

Resolve 返回 500 错误

无论什么异常,都返回 500 Internal Server Error。

func (*DefaultExceptionResolver) Supports

func (r *DefaultExceptionResolver) Supports(err error) bool

Supports 支持所有异常

始终返回 true,确保这个解析器可以处理任何异常。

type DefaultMetricsRecorder

type DefaultMetricsRecorder struct {
	// contains filtered or unexported fields
}

DefaultMetricsRecorder 默认指标记录器实现

DefaultMetricsRecorder 是 MetricsRecorder 接口的默认实现。 它使用原子操作来记录异常计数,适合开发和测试环境。 使用 sync.Map + atomic.Int64 实现无锁高并发计数。

Example
package main

import (
	"fmt"

	"github.com/xudefa/enhance/exception"
)

func main() {
	metrics := exception.NewDefaultMetricsRecorder()

	metrics.RecordException("TestError", 500)
	metrics.RecordException("TestError", 500)

	count := metrics.(*exception.DefaultMetricsRecorder).GetCount("TestError", 500)
	fmt.Printf("Count: %d\n", count)

}

func (*DefaultMetricsRecorder) GetCount

func (m *DefaultMetricsRecorder) GetCount(exceptionType string, statusCode int) int

GetCount 获取计数(用于测试)

返回指定异常类型和状态码的计数。 注意:这个方法主要用于测试,生产环境应该使用更专业的指标系统。

func (*DefaultMetricsRecorder) RecordException

func (m *DefaultMetricsRecorder) RecordException(exceptionType string, statusCode int)

RecordException 记录异常指标

根据异常类型和状态码生成键,并增加对应的计数。 键的格式为 "exceptionType:statusCode"。

type ErrorCode

type ErrorCode struct {
	Code    int    // HTTP 状态码
	Message string // 用户可见消息
	Detail  string // 开发者调试信息
}

ErrorCode 业务错误码。

定义统一的错误码体系,包含 HTTP 状态码、用户可见消息和开发者调试信息。

示例:

var (
    ErrUserNotFound     = ErrorCode{404, "用户不存在", "user_not_found"}
    ErrInvalidParameter = ErrorCode{400, "参数错误", "invalid_parameter"}
)

func GetErrorCode

func GetErrorCode(detail string) (ErrorCode, bool)

GetErrorCode 从全局注册表获取错误码

func (ErrorCode) Error

func (e ErrorCode) Error() string

func (ErrorCode) WithDetail

func (e ErrorCode) WithDetail(detail string) ErrorCode

WithDetail 创建带有自定义详情的错误码。

func (ErrorCode) WithMessage

func (e ErrorCode) WithMessage(msg string) ErrorCode

WithMessage 创建带有自定义消息的错误码。

type ErrorCodeExceptionResolver

type ErrorCodeExceptionResolver struct {
	// contains filtered or unexported fields
}

ErrorCodeExceptionResolver 错误码异常解析器

将 ErrorCode 类型的错误转换为统一的错误响应。

func NewErrorCodeExceptionResolver

func NewErrorCodeExceptionResolver() *ErrorCodeExceptionResolver

NewErrorCodeExceptionResolver 创建错误码异常解析器

func (*ErrorCodeExceptionResolver) Order

func (r *ErrorCodeExceptionResolver) Order() int

Order 返回解析器优先级

func (*ErrorCodeExceptionResolver) Resolve

Resolve 解析错误码并返回错误响应

func (*ErrorCodeExceptionResolver) Supports

func (r *ErrorCodeExceptionResolver) Supports(err error) bool

Supports 判断是否能处理该错误

type ErrorCodeRegistry

type ErrorCodeRegistry struct {
	// contains filtered or unexported fields
}

ErrorCodeRegistry 错误码注册表。

管理所有业务错误码的注册和查询。 使用 sync.Map 优化读多写少场景的并发性能。

func GlobalErrorCodeRegistry

func GlobalErrorCodeRegistry() *ErrorCodeRegistry

GlobalErrorCodeRegistry 返回全局错误码注册表

func NewErrorCodeRegistry

func NewErrorCodeRegistry() *ErrorCodeRegistry

NewErrorCodeRegistry 创建错误码注册表

func (*ErrorCodeRegistry) Get

func (r *ErrorCodeRegistry) Get(detail string) (ErrorCode, bool)

Get 根据开发者调试信息获取错误码

func (*ErrorCodeRegistry) GetAll

func (r *ErrorCodeRegistry) GetAll() []ErrorCode

GetAll 获取所有注册的错误码

func (*ErrorCodeRegistry) MustGet

func (r *ErrorCodeRegistry) MustGet(detail string) ErrorCode

MustGet 根据开发者调试信息获取错误码,不存在则 panic

func (*ErrorCodeRegistry) Register

func (r *ErrorCodeRegistry) Register(code ErrorCode)

Register 注册错误码

type ErrorResponse

type ErrorResponse struct {
	Code      int    `json:"code"`                // HTTP 状态码
	Message   string `json:"message"`             // 错误消息
	RequestID string `json:"requestId,omitempty"` // 请求 ID
	TraceID   string `json:"traceId,omitempty"`   // 链路追踪 ID
	Details   any    `json:"details,omitempty"`   // 错误详情
	Timestamp int64  `json:"timestamp"`           // 时间戳
}

ErrorResponse 统一错误响应。

所有异常处理最终都转换为此结构体,确保 API 错误响应格式一致。

func NewErrorResponse

func NewErrorResponse(code int, message, requestID, traceID string, details any) *ErrorResponse

NewErrorResponse 创建新的错误响应

创建一个 ErrorResponse 实例,自动设置时间戳为当前时间。

参数: - code: HTTP 状态码 - message: 错误消息 - requestID: 请求 ID(可选) - traceID: 追踪 ID(可选) - details: 详细信息(可选,可以是任意类型)

返回一个初始化好的 ErrorResponse 实例。

func (*ErrorResponse) ToJSON

func (e *ErrorResponse) ToJSON() ([]byte, error)

ToJSON 将错误响应转换为JSON字节

type ErrorResponseBuilder

type ErrorResponseBuilder struct {
	// contains filtered or unexported fields
}

ErrorResponseBuilder 错误响应构建器

func NewErrorResponseBuilder

func NewErrorResponseBuilder() *ErrorResponseBuilder

NewErrorResponseBuilder 创建错误响应构建器

func (*ErrorResponseBuilder) Build

Build 构建错误响应

func (*ErrorResponseBuilder) Code

Code 设置HTTP状态码

func (*ErrorResponseBuilder) Details

func (b *ErrorResponseBuilder) Details(details any) *ErrorResponseBuilder

Details 设置错误详情

func (*ErrorResponseBuilder) Message

func (b *ErrorResponseBuilder) Message(message string) *ErrorResponseBuilder

Message 设置错误消息

func (*ErrorResponseBuilder) RequestID

func (b *ErrorResponseBuilder) RequestID(requestID string) *ErrorResponseBuilder

RequestID 设置请求ID

func (*ErrorResponseBuilder) ToJSON

func (b *ErrorResponseBuilder) ToJSON() ([]byte, error)

ToJSON 将错误响应转换为JSON字节

func (*ErrorResponseBuilder) TraceID

func (b *ErrorResponseBuilder) TraceID(traceID string) *ErrorResponseBuilder

TraceID 设置链路追踪ID

type ExceptionHandler

type ExceptionHandler interface {
	// Handle 处理异常并返回统一错误响应。
	Handle(ctx context.Context, err error, response ResponseWriter) *ErrorResponse

	// RegisterResolver 注册通用异常解析器。
	RegisterResolver(resolver ExceptionResolver)

	// RegisterException 为指定异常类型注册解析器。
	RegisterException(exceptionType reflect.Type, resolver ExceptionResolver)

	// RegisterHandlerFunc 为指定异常类型注册处理函数。
	RegisterHandlerFunc(exceptionType reflect.Type, handler func(ctx context.Context, err error) *ErrorResponse)
}

ExceptionHandler 异常处理器接口。

核心异常处理入口,支持注册自定义解析器和处理函数。

func NewDefaultExceptionHandler

func NewDefaultExceptionHandler(opts ...Option) ExceptionHandler

NewDefaultExceptionHandler 创建默认异常处理器。

支持通过 Option 函数配置日志记录器、指标记录器和堆栈跟踪选项。 默认情况下,会注册内置异常解析器和默认异常解析器。

示例:

handler := exception.NewDefaultExceptionHandler(
	exception.WithLogger(logger),
	exception.WithMetricsRecorder(metrics),
	exception.WithIncludeStackTrace(true),
)

type ExceptionHandlerBuilder

type ExceptionHandlerBuilder struct {
	// contains filtered or unexported fields
}

ExceptionHandlerBuilder 异常处理器构建器,支持链式配置

func NewExceptionHandlerBuilder

func NewExceptionHandlerBuilder() *ExceptionHandlerBuilder

NewExceptionHandlerBuilder 创建异常处理器构建器

func (*ExceptionHandlerBuilder) Build

Build 构建异常处理器

func (*ExceptionHandlerBuilder) ExceptionHandler

func (b *ExceptionHandlerBuilder) ExceptionHandler(exceptionType reflect.Type, handler func(ctx context.Context, err error) *ErrorResponse) *ExceptionHandlerBuilder

ExceptionHandler 为指定异常类型注册处理函数

func (*ExceptionHandlerBuilder) IncludeStackTrace

func (b *ExceptionHandlerBuilder) IncludeStackTrace(include bool) *ExceptionHandlerBuilder

IncludeStackTrace 设置是否包含堆栈跟踪

func (*ExceptionHandlerBuilder) Logger

Logger 设置日志记录器

func (*ExceptionHandlerBuilder) MetricsRecorder

func (b *ExceptionHandlerBuilder) MetricsRecorder(recorder MetricsRecorder) *ExceptionHandlerBuilder

MetricsRecorder 设置指标记录器

func (*ExceptionHandlerBuilder) MustBuild

MustBuild 构建异常处理器,失败则panic

func (*ExceptionHandlerBuilder) Resolver

Resolver 添加异常解析器

type ExceptionHandlerConfig

type ExceptionHandlerConfig struct {
	Logger            Logger          // 日志记录器
	MetricsRecorder   MetricsRecorder // 指标记录器
	IncludeStackTrace bool            // 是否在响应中包含堆栈跟踪
}

ExceptionHandlerConfig 异常处理器配置。

type ExceptionResolver

type ExceptionResolver interface {
	// Resolve 解析异常并返回错误响应。
	Resolve(ctx context.Context, err error) *ErrorResponse

	// Supports 判断是否能处理该异常。
	Supports(err error) bool

	// Order 返回解析器优先级,值越小优先级越高。
	Order() int
}

ExceptionResolver 异常解析器接口。

解析异常并生成统一错误响应,支持优先级排序。 多个解析器按 Order() 返回值从小到大依次尝试。

func NewBuiltinExceptionResolver

func NewBuiltinExceptionResolver() ExceptionResolver

NewBuiltinExceptionResolver 创建内置解析器

返回一个 BuiltinExceptionResolver 实例。

func NewDefaultExceptionResolver

func NewDefaultExceptionResolver() ExceptionResolver

NewDefaultExceptionResolver 创建默认解析器

返回一个 DefaultExceptionResolver 实例。

type KeyValue

type KeyValue struct {
	Key   string // 键名
	Value any    // 值
}

KeyValue 日志键值对。

type Logger

type Logger interface {
	// Error 记录错误日志。
	Error(ctx context.Context, msg string, keyValues ...KeyValue)
}

Logger 日志接口。

抽象层,不依赖具体日志实现,支持 slog、zap 等多种日志框架适配。

type MetricsRecorder

type MetricsRecorder interface {
	// RecordException 记录一次异常事件。
	RecordException(exceptionType string, statusCode int)
}

MetricsRecorder 指标记录器接口。

抽象层,用于记录异常指标到监控系统。

func NewDefaultMetricsRecorder

func NewDefaultMetricsRecorder() MetricsRecorder

NewDefaultMetricsRecorder 创建默认指标记录器

返回一个 DefaultMetricsRecorder 实例。

type Option

type Option func(*ExceptionHandlerConfig)

Option 配置选项。

Option 是用于配置 ExceptionHandler 的函数类型。

func WithIncludeStackTrace

func WithIncludeStackTrace(include bool) Option

WithIncludeStackTrace 设置是否包含堆栈信息。

配置是否在错误响应中包含堆栈跟踪信息。 注意:生产环境中建议关闭此选项以避免泄露敏感信息。

func WithLogger

func WithLogger(logger Logger) Option

WithLogger 设置日志记录器。

为异常处理器配置日志记录器,所有异常处理都会被记录。

func WithMetricsRecorder

func WithMetricsRecorder(recorder MetricsRecorder) Option

WithMetricsRecorder 设置指标记录器。

为异常处理器配置指标记录器,所有异常都会被记录为指标。

type ResolverChain

type ResolverChain struct {
	// contains filtered or unexported fields
}

ResolverChain 解析器链

ResolverChain 管理多个 ExceptionResolver,并按优先级顺序执行它们。 当处理异常时,会遍历解析器链,找到第一个支持该异常的解析器进行处理。

func NewResolverChain

func NewResolverChain() *ResolverChain

NewResolverChain 创建新的解析器链

创建一个空的解析器链,可以通过 AddResolver 方法添加解析器。

func (*ResolverChain) AddResolver

func (c *ResolverChain) AddResolver(resolver ExceptionResolver)

AddResolver 添加解析器(自动按 Order 排序)

将解析器添加到链中,并自动按照 Order 值进行排序。 Order 值越小,优先级越高,会先被调用。

func (*ResolverChain) GetResolvers

func (c *ResolverChain) GetResolvers() []ExceptionResolver

GetResolvers 获取所有解析器

返回当前解析器链中的所有解析器,按优先级排序。 返回的是内部切片的副本,避免调用方修改内部状态。

func (*ResolverChain) Resolve

func (c *ResolverChain) Resolve(ctx context.Context, err error) *ErrorResponse

Resolve 查找第一个支持的解析器并解析异常

遍历解析器链,找到第一个 Supports 返回 true 的解析器, 并调用其 Resolve 方法处理异常。如果没有找到支持的解析器,返回 nil。 先在锁内获取快照再释放锁,避免在持有锁时调用用户代码导致死锁。

type ResponseWriter

type ResponseWriter interface {
	// SetStatusCode 设置 HTTP 状态码。
	SetStatusCode(code int)

	// SetHeader 设置响应头。
	SetHeader(key, value string)

	// Write 写入响应体。
	Write(data []byte) error

	// Context 返回请求上下文。
	//
	// 如果实现不支持上下文,应返回 context.Background()。
	Context() context.Context
}

ResponseWriter 响应写入器接口。

抽象层,适配不同 HTTP 框架的响应写入。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL