go
func ErrorMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter,魔兽争霸透视 r *http.Request) {
next.ServeHTTP(w, r) if err := GetRequestError(r); err != nil { switch { case errors.Is(err, ErrUserNotFound): WriteJSONError(w, http.StatusNotFound, err) case errors.Is(err, ErrOrderConflict): WriteJSONError(w, http.StatusConflict, err) default: WriteJSONError(w, http.StatusInternalServerError, errors.New("internal server error")) } } })}
这个看似简单的错误实际包含多层含义 :
- 可能是正常的业务空状态(如用户未配置信息)
- 也可能是真正的数据异常(按ID查询不存在的记录)推荐处理方式
:go
func (r UserRepo) GetByID(ctx context.Context, id int64) (User, error) {
const query = SELECT...
var user Usererr := r.db.QueryRowContext(ctx, query, id).Scan(&user.ID, &user.Name) switch { case errors.Is(err, sql.ErrNoRows): return nil, ErrUserNotFound.WithMeta("user_id", id) case err != nil: return nil, fmt.Errorf("query user: %w", err) } return &user, nil}
| 错误类型 | 判断方法 | 处理建议 |
|-----------------------|--------------------------|--------------------------|
| 连接超时 | errors.Is(err, context.DeadlineExceeded) | 添加重试机制 |
| 唯一约束冲突 | 检查错误字符串或数据库错误码 | 转换为业务冲突错误类型 |
| 事务冲突 | 判断sql.ErrTxDone | 区分重试与业务回滚 |作者经验谈:在实际项目中 ,微信加粉统计系统、
↓点击下方了解更多↓🔥《微信域名检测接口、这种错误处理方式暴露了三个典型问题:
错误信息模糊:原始错误直接暴露给调用方 处理逻辑重复:每个DAO方法都在重复判断相同错误 上下文缺失:无法追溯错误发生的业务场景go // 典型的问题代码示例 err := db.QueryRow("SELECT...").Scan(&data) if err != nil { if err == sql.ErrNoRows { return nil, fmt.Errorf("not found") } return nil, err }
原始层
:保留数据库驱动原始错误
go // 使用%w保留错误链 if err := row.Scan(...); err != nil { return fmt.Errorf("scan order data: %w", err) }业务语义层
:定义领域错误类型
go var ( ErrOrderNotFound = errors.NewClass("order not found") ErrOrderConflict = errors.NewClass("order conflict") )元信息层
:附加上下文数据
go return ErrOrderNotFound. WithMeta("order_id", orderID). WithCause(err)go
func (r *OrderRepository) UpdateOrderStatus(ctx context.Context, orderID string, status int) error {
const query = UPDATE orders SET status=$1 WHERE id=$2result, err := r.db.ExecContext(ctx, query, status, orderID) if err != nil { if isDuplicateError(err) { // 自定义判断函数 return ErrOrderConflict.WithCause(err) } return fmt.Errorf("update order status: %w", err) } rowsAffected, _ := result.RowsAffected() if rowsAffected == 0 { return ErrOrderNotFound.WithMeta("order_id", orderID) } return nil}
评估错误处理是否到位的checklist:
1. 是否保留了完整的错误链(errors.Is()可追溯)
2. 敏感信息是否已过滤(如SQL语句)
3. 日志是否包含足够排查信息
4. 相同错误是否在多层重复处理
5. 错误类型是否具有明确的业务语义最终建议:在项目初期就建立《错误处理规范》,约定错误分类、辅助器带这将大幅降低后期的维护成本。提升网站流量排名、为什么需要专门处理数据库错误
在Web服务开发中,
对于Web服务,封装方式和日志格式,
(责任编辑:手游中心)