在上一遍 Gin 捕获异常中间件、封装返回自定义格式数据 | Go 主题月
通过 panic 方式 抛出异常,通过 recovery 方式进行捕获返回
在看到 Go-advice 发现原来 panic 方式不合理
不要(在生产环境)使用 panic()
显式处理错误
尽早返回,而不是使用深嵌套
开始调整
所以在原来基础之上对使用到 panic 方式进行调整
common.go 修改前
func Success(c *gin.Context, data interface{}) {
c.JSON(http.StatusOK, gin.H{
"code": http.StatusOK,
"data": data,
"message": "请求成功",
})
}
common.go 修改后
func JSON(c *gin.Context, data interface{}) {
c.JSON(http.StatusOK, data)
c.Abort()
}
已注册接口为例
修改前
func (ac *AccountController) Register(c *gin.Context) {
var registerInfo model.RegisterInfo
if err := c.BindJSON(®isterInfo); err != nil {
log.Println(err.Error())
panic(api.ErrParam.WithErrMsg(err.Error()))
}
log.Printf("receiver param %s", registerInfo)
accountService := service.AccountService{}
accountService.Register(®isterInfo)
common.Success(c, 1)
}
修改后
func (ac *AccountController) Register(c *gin.Context) {
var registerInfo model.RegisterInfo
if err := c.BindJSON(®isterInfo); err != nil {
log.Println(err.Error())
common.FailedParam(c)
return
}
accountService := service.AccountService{}
common.JSON(c, accountService.Register(®isterInfo))
}
注册逻辑调整
AccountService Register 方法调整,返回 api.JsonResult 格式
- 在发生错误时,及时返回错误提示,使用 api.JsonResult 结构体封装
func (us *AccountService) Register(registerInfo *model.RegisterInfo) *api.JsonResult {
log.Printf("receiver param %s", registerInfo)
password := registerInfo.Password
worker, err := util.NewWorker(16)
if err != nil {
log.Print(err)
return api.JsonError(api.UserAddFailErr)
}
userDao := dao.UserDao{DbEngine: engine.GetOrmEngine()}
exist, err := userDao.QueryByPhone(registerInfo.Phone)
log.Printf("check Phone %v %v", exist, err)
if exist || err != nil {
return api.JsonError(api.PhoneExistErr)
}
exist, err = userDao.QueryByUserName(registerInfo.UserName)
log.Printf("check UserName %v %v", exist, err)
if exist || err != nil {
return api.JsonError(api.UserNameExistErr)
}
// ....
result, err := userDao.InsertUser(userInfo)
log.Printf("add user result %v error %v", result, err)
if err != nil {
return api.JsonError(api.UserAddFailErr)
}
// ....
result, err = userDao.InsertPassword(passwordInfo)
log.Printf("add password result %v error %v", result, err)
if err != nil {
return api.JsonError(api.UserAddFailErr)
}
return api.JsonSuccess()
}
返回 JSON 结构数据
package api
type JsonResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
Success bool `json:"success"`
}
func Json(code int, message string, data interface{}, success bool) *JsonResult {
return &JsonResult{
Code: code,
Message: message,
Data: data,
Success: success,
}
}
func JsonData(data interface{}) *JsonResult {
return &JsonResult{
Code: 200,
Data: data,
Success: true,
Message: "请求成功",
}
}
func JsonSuccess() *JsonResult {
return &JsonResult{
Code: 200,
Data: nil,
Success: true,
Message: "请求成功",
}
}
func JsonError(err *CodeError) *JsonResult {
return &JsonResult{
Code: err.Code,
Message: err.Message,
Data: err.Data,
Success: false,
}
}
func (json *JsonResult) JsonWithMsg(message string) *JsonResult {
json.Message = message
return json
}
func (json *JsonResult) JsonWithCode(code int) *JsonResult {
json.Code = code
return json
}
func (json *JsonResult) JsonWithData(data interface{}) *JsonResult {
json.Data = data
return json
}
统一错误码
package api
import (
"strconv"
)
var (
OK = NewError(200, "请求成功")
// 业务异常
UserAddFailErr = NewError(20001, "添加用户失败")
// 其他更多 业务异常 ......
)
func NewError(code int, text string) *CodeError {
return &CodeError{code, text, nil}
}
func NewErrorData(code int, text string, data interface{}) *CodeError {
return &CodeError{code, text, data}
}
type CodeError struct {
Code int
Message string
Data interface{}
}
func (e *CodeError) Error() string {
return strconv.Itoa(e.Code) + ": " + e.Message
}
总结
去除原来 panic + recovery 方式返回错误,这样有点不可控
在程序发生 err 时,err != nil,判断错误,直接返回错误信息,不再往下执行,把状态变为可控
本次调整 git 记录可查看