统一响应与错误码封装
接口返回如果不统一,前端每个接口都要写不同的解析分支。GoFrame v2 规范路由场景下,官方默认中间件 ghttp.MiddlewareHandlerResponse 已把响应收敛成 {code, message, data} 结构;本章讲清默认行为,并给出“自定义统一中间件 + 业务错误码”的封装思路。
默认响应结构
框架的默认响应体定义(源码可见):
// ghttp.DefaultHandlerResponse
type DefaultHandlerResponse struct {
Code int `json:"code"`
Message string `json:"message"`
Data any `json:"data"`
}
默认中间件逻辑:handler 返回 err == nil 时输出 code=0、data 为业务结果;err != nil 时从错误中取错误码(gerror.Code(err)),无错误码的错误按内部错误处理并输出错误信息。
自定义统一中间件
默认结构往往不够用:要把业务码映射为 HTTP 状态码、记录错误日志、避免内部细节泄露给客户端。自定义时官方提示用 r.GetHandlerResponse() 取业务结果:
package middleware
import (
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data any `json:"data"`
}
// HandlerResponse 统一响应中间件(全局 s.Use 挂载)
func HandlerResponse(r *ghttp.Request) {
r.Middleware.Next()
if r.Response.BufferLength() > 0 { // 业务已自行写回内容
return
}
var (
err = r.GetError()
res = r.GetHandlerResponse()
)
if err != nil {
code := gerror.Code(err) // 业务码在错误链上则原样透出
g.Log().Errorf(r.Context(), "handler error: %+v", err)
r.Response.WriteJson(Response{Code: code.Code(), Message: err.Error()})
return
}
r.Response.WriteJson(Response{Code: 0, Message: "OK", Data: res})
}
main 里 s.Use(middleware.HandlerResponse) 后,所有规范路由的返回都被包装,出错路径统一兜底,不再出现裸堆栈或空响应。
错误码常量:gcode 与 gerror
GoFrame 的错误码模型是 gcode.Code 接口,gerror 提供带错误码的错误创建与包装:
package code
import "github.com/gogf/gf/v2/errors/gcode"
// 官方约定:<1000 为框架预留,业务错误码请使用 >1000
var (
UserNotExist = gcode.New(1001, "用户不存在", nil)
UserPasswordErr = gcode.New(1002, "用户名或密码错误", nil)
ArticleNotFound = gcode.New(2001, "文章不存在", nil)
)
package service
import (
"github.com/gogf/gf/v2/errors/gerror"
"project/internal/code"
)
func Login(ctx context.Context, name, pass string) error {
user := GetUserByName(ctx, name)
if user == nil {
return gerror.NewCode(code.UserNotExist) // 业务层只抛业务码
}
return nil
}
注意点
- 统一中间件模式下,handler 只要
return res, nil或return nil, err。 - HTTP 状态码与业务码解耦:业务失败常返回 200 + 非零 code;需要 401/404 语义时在中间件按错误码映射状态码;流式响应/已写缓冲的请求不要重复包装。
小结
统一响应 = 一个全局后置中间件 + {code,message,data};错误码 = gcode 常量 + gerror 抛出。二者配合后业务层只关心“抛什么业务码”,传输层永远输出稳定结构。默认结构细节以官方文档 goframe.org 为准。