...
Code Block |
---|
|
type pErr struct {
maps map[int]string
}
var Err = &pErr{
maps: map[int]string{
0: "请求成功",
10001: "用户名或密码错误",
10002: "用户不存在",
99999: "未知错误",
},
}
// GetMsg 获取code码对应的msg
func (c *pErr) GetMsg(code int) string {
return c.maps[code]
}
// Skip 抛出一个业务级别的错误,不会打印错误堆栈信息
func (c *pErr) Skip(code int, msg ...string) (err error) {
var msgStr string
if len(msg) == 0 {
msgStr = c.GetMsg(code)
} else {
msg = append([]string{c.GetMsg(code)}, msg...)
msgStr = strings.Join(msg, ", ")
}
// NewWithOption 在低版本的 gf 上不存在,请改用 NewOption
return gerror.NewWithOption(gerror.Option{
Stack: false,
Text: msgStr,
Code: gcode.New(code, "", nil),
})
}
// Sys 抛出一个系统级别的错误,使用code码:99999,会打印错误堆栈信息抛出一个系统级别的错误,使用特殊的code码:99999
// msg!!! 接受string和error类型使用该方法时,它会打印错误堆栈信息到日志,但是一定不要把任何错误信息抛出到客户端,防止泄露系统信息
// !!! 使用该方法传入error类型时,一定要注意不要泄露系统信息推荐做法是在后置中间件中捕获 code 99999 的错误,然后返回给客户端一个统一的错误提示
func (c *pErr) Sys(msg ...interface{}err error) error {
var (
code = 99999
msgSlice = []string{
c.GetMsg(code),
}
)
if len(msg) != 0 {
for _, v := range msg {
switch a := v.(type) {
case error:
msgSlice = append(msgSlice, a.Error())
case string:
msgSlice = append(msgSlice, a)
}
}
}
msgStr := strings.Join(msgSlice, ", ")
return gerror.NewCode(gcode.New(codeCodeErrSys, "", nil), msgStrerr.Error())
} |
统一响应数据中间件
设计统一响应数据的中间件,并且注入到 HTTP 请求流程中:
...
Code Block |
---|
|
type sMiddleware struct {
}
func init() {
service.RegisterMiddleware(New())
}
func New() *sMiddleware {
return &sMiddleware{}
}
type Response struct {
Code int `json:"code" dc:"业务码"`
Message string `json:"message" dc:"业务码说明"`
Data interface{} `json:"data" dc:"返回的数据"`
}
func (s *sMiddleware) Response(r *ghttp.Request) {
r.Middleware.Next()
if r.Response.BufferLength() > 0 {
return
}
// 先过滤掉服务器内部错误
if r.Response.Status >= http.StatusInternalServerError {
// 清除掉缓存区,防止服务器信息泄露到客户端
r.Response.ClearBuffer()
r.Response.Writeln("服务器打盹了,请稍后再来找他!")
}
var (
res = r.GetHandlerResponse()
err = r.GetError()
code = gerror.Code(err)
codeInt = code.Code()
msg string
)
if err != nil {
// 如果是系统错误,不要把错误信息抛出到客户端,防止泄露系统信息
if codeInt == packed.CodeErrSys {
msg = packed.Err.GetSysMsg()
} else {
msg = err.Error()
}
} else {
code = gcode.CodeOK
msg = packed.Err.GetMsg(code.Code())
}
r.Response.WriteJson(Response{
Code: code.Code(),
Message: msg,
Data: res,
})
} |
...
Code Block |
---|
|
func (s *sException) Business() error {
return packed.Err.Skip(10001)
}
// System 这里我们对 gjson.Decode() 传入错误数据,用来模拟组件内部抛出err
func (s *sException) System() error {
_, err := gjson.Decode("")
if err != nil {
return packed.Err.Sys("可选自定义信息"err)
}
return nil
} |
结果展示:
Code Block |
---|
|
Business
{
"code": 10001,
"message": "用户名或密码错误",
"data": null
}
System
{
"code": 99999,
"message": "未知错误, 可选自定义信息",
"data": null
} |
用户名或密码错误的业务异常也不会再抛出堆栈异常了:
...