
go自定义异常
text
your-project/
├── errors/
│ ├── errors.go # 错误定义和核心结构
│ ├── predefined.go # 预定义错误
│ ├── utils.go # 工具函数
├── go.mod
└── main.goerrors.go
go
package errors
import (
"fmt"
)
// CustomError 自定义错误类型
type CustomError struct {
HTTPCode int `json:"-"` // HTTP 状态码,不序列化到 JSON
Code int `json:"code"` // 业务错误码
Message string `json:"message"` // 错误信息
Details string `json:"details,omitempty"` // 错误详情(可选)
Err error `json:"-"` // 原始错误(用于日志,不序列化到 JSON)
}
// Error 实现 error 接口
func (e *CustomError) Error() string {
if e.Err != nil {
return fmt.Sprintf("HTTPCode: %d, Code: %d, Message: %s, Original: %v",
e.HTTPCode, e.Code, e.Message, e.Err)
}
return fmt.Sprintf("HTTPCode: %d, Code: %d, Message: %s",
e.HTTPCode, e.Code, e.Message)
}
// Unwrap 实现 errors.Unwrap 接口,便于错误链处理
func (e *CustomError) Unwrap() error {
return e.Err
}
// WithDetails 添加错误详情
func (e *CustomError) WithDetails(details string) *CustomError {
e.Details = details
return e
}
// WithError 添加原始错误
func (e *CustomError) WithError(err error) *CustomError {
e.Err = err
return e
}
// New 创建新的自定义错误
func New(httpCode, code int, message string) *CustomError {
return &CustomError{
HTTPCode: httpCode,
Code: code,
Message: message,
}
}predefined.go
go
package errors
import "net/http"
// 通用错误
var (
ErrBadRequest = New(http.StatusBadRequest, 40000, "请求参数错误")
ErrUnauthorized = New(http.StatusUnauthorized, 40100, "未授权访问")
ErrForbidden = New(http.StatusForbidden, 40300, "禁止访问")
ErrNotFound = New(http.StatusNotFound, 40400, "资源不存在")
ErrInternalServer = New(http.StatusInternalServerError, 50000, "服务器内部错误")
ErrServiceUnavailable = New(http.StatusServiceUnavailable, 50300, "服务暂时不可用")
)
// 业务相关错误
var (
ErrUserNotFound = New(http.StatusNotFound, 40401, "用户不存在")
ErrUserExists = New(http.StatusBadRequest, 40001, "用户已存在")
ErrInvalidPassword = New(http.StatusBadRequest, 40002, "密码错误")
ErrTokenExpired = New(http.StatusUnauthorized, 40101, "令牌已过期")
ErrTokenInvalid = New(http.StatusUnauthorized, 40102, "无效令牌")
ErrPermissionDenied = New(http.StatusForbidden, 40301, "权限不足")
)
// 数据库相关错误
var (
ErrDBQuery = New(http.StatusInternalServerError, 50001, "数据库查询失败")
ErrDBInsert = New(http.StatusInternalServerError, 50002, "数据库插入失败")
ErrDBUpdate = New(http.StatusInternalServerError, 50003, "数据库更新失败")
ErrDBDelete = New(http.StatusInternalServerError, 50004, "数据库删除失败")
ErrDBConn = New(http.StatusInternalServerError, 50005, "数据库连接失败")
)
// 文件操作相关错误
var (
ErrFileNotFound = New(http.StatusNotFound, 40402, "文件不存在")
ErrFileRead = New(http.StatusInternalServerError, 50006, "文件读取失败")
ErrFileWrite = New(http.StatusInternalServerError, 50007, "文件写入失败")
ErrFileSizeExceed = New(http.StatusBadRequest, 40003, "文件大小超出限制")
ErrFileTypeInvalid = New(http.StatusBadRequest, 40004, "文件类型不支持")
)utils.go
go
package errors
import (
"encoding/json"
"log"
"net/http"
)
// IsCustomError 判断是否为自定义错误
func IsCustomError(err error) bool {
_, ok := err.(*CustomError)
return ok
}
// FromError 从标准 error 转换,如果不是 CustomError 则返回内部服务器错误
func FromError(err error) *CustomError {
if customErr, ok := err.(*CustomError); ok {
return customErr
}
return ErrInternalServer.WithError(err).WithDetails(err.Error())
}
// ToJSON 将错误转换为 JSON 字符串
func (e *CustomError) ToJSON() string {
jsonBytes, err := json.Marshal(e)
if err != nil {
log.Printf("序列化错误失败: %v", err)
return `{"code":50000,"message":"序列化错误失败"}`
}
return string(jsonBytes)
}
// WriteHTTP 将错误写入 HTTP 响应
func (e *CustomError) WriteHTTP(w http.ResponseWriter) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(e.HTTPCode)
w.Write([]byte(e.ToJSON()))
}
// LogError 记录错误日志(包含原始错误信息)
func (e *CustomError) LogError() {
if e.Err != nil {
log.Printf("自定义错误: %s, 详情: %s, 原始错误: %v", e.Message, e.Details, e.Err)
} else {
log.Printf("自定义错误: %s, 详情: %s", e.Message, e.Details)
}
}
// LogErrorWithRequest 记录错误日志(包含请求信息)
func (e *CustomError) LogErrorWithRequest(r *http.Request) {
if e.Err != nil {
log.Printf("请求错误 - 方法: %s, 路径: %s, 错误: %s, 详情: %s, 原始错误: %v",
r.Method, r.URL.Path, e.Message, e.Details, e.Err)
} else {
log.Printf("请求错误 - 方法: %s, 路径: %s, 错误: %s, 详情: %s",
r.Method, r.URL.Path, e.Message, e.Details)
}
}
// GetOriginalError 获取原始错误(如果存在)
func (e *CustomError) GetOriginalError() error {
return e.Err
}
// Is 检查错误链中是否包含目标错误
func Is(err, target error) bool {
if err == target {
return true
}
if customErr, ok := err.(*CustomError); ok && customErr.Err != nil {
return Is(customErr.Err, target)
}
return false
}
