5

从零开发区块链应用(四)--自定义业务错误信息

 2 years ago
source link: https://learnblockchain.cn/article/3449
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一、如何自定义错误信息

1.1 为什么要自定义自己的错误信息

在实际开发中引入错误码有如下好处:

  • 可以非常方便地定位问题和定位代码行(看到错误码知道什么意思,通过错误码可以定位到错误码所在行);

  • 如果API对外开放,有错误码将会更专业;

  • 错误码包含一定的信息,通过错误码可以判断出错误级别、错误模块和具体错误信息;

  • 在实际业务开发中,一个条错误信息需要包含两部分内容:直接展示给用户的 message 和用于开发人员 debug 的 error 。message可能会直接展示给用户,error 是用于 debug 的错误信息,可能包含敏感/内部信息,不宜对外展示;

  • 业务开发过程中,可能需要判断错误是哪种类型以便做相应的逻辑处理,通过定制的错误码很容易做到这点;

  • Go 中的 HTTP 服务器开发都是引用 net/http 包,该包中只有 60 个错误码,基本都是跟 HTTP 请求相关的。在大型系统中,这些错误码完全不够用,而且跟业务没有任何关联,满足不了业务需求。

    在实际开发中,一个错误类型通常包含两部分:Code 部分,用来唯一标识一个错误;Message 部分,用来展示错误信息,这部分错误信息通常供前端直接展示。

1.2 错误码设计

一个良好结构的错误码有助于简化问题描述, 当前设计的错误码共有五位, 结构如下:

1 00 01

服务级错误 服务模块 具体错误代码

  • 第一位是服务级别, 1 为系统错误, 2 为普通错误。通常由用户非法操作引起;
  • 服务模块为两位数:一个大型系统的服务模块通常不超过两位数,如果超过,说明这个系统该拆分了;模块不是指 Go 中的模块, 而是指代某个范围, 比如数据库错误, 认证错误;
  • 错误码为两位数:防止一个模块定制过多的错误码,后期不好维护,一般是具体错误, 比如数据库错误中的插入错误, 找不到数据等。
  • code = 0 说明是正确返回,code > 0 说明是错误返回
  • 错误通常包括系统级错误码和服务级错误码
  • 建议代码中按服务模块将错误分类
  • 错误码均为 >= 0 的数

二、 实际开发错误处理

2.1 代码实现

在项目目录下新建一个 apicommon 目录, 并创建相应的模块。

package apicommon

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

type Response struct {
	Error *Error      `json:"error,omitempty"`
	Msg   string      `json:"message"`
	Code  int64       `json:"code"`
	Data  interface{} `json:"result,omitempty"`
}

type Error struct {
	Code int64  `json:"code"`   // 错误码
	Msg  string `json:"message"`  // 返回给用户的信息
	Data string `json:"data,omitempty"` // 保存的内部错误信息
}

// ReturnErrorResponse 返回错误
func ReturnErrorResponse(ctx *gin.Context, errmsg string, code int64, err string) {
	response := &Response{
		Error: &Error{
			Msg:  errmsg,   
			Code: code,
			Data: err,
		},
	}
	ctx.JSON(http.StatusOK, response)
	return
}

2.2 错误码实战

上面介绍了错误码的一些知识,这一部分讲开发中是如何使用 自定义错误函数来处理错误信息的。为了演示,我们新增一个根据手机号获取验证码的 API:

handler/router.go 中添加路由

func RouterStart() {

	gin.SetMode(gin.ReleaseMode) //设置gin模式

	router := gin.New()

	personal := router.Group("/api/v2")
	{
		personal.POST("/sso/getAuthCode", handler.GetAuthCode)
	}	
	logger.Info("API server start", "listen", config.Conf.Console.Port)
	router.Run(config.Conf.Console.Port)
}

handler 目录下增加业务处理函数 handler/personal.go

//手机号校验
func VerifyMobileFormat(mobileNum string) bool {
	regular := "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$"
	reg := regexp.MustCompile(regular)
	return reg.MatchString(mobileNum)
}

// 根据手机号获取验证码
func GetAuthCode(ctx *gin.Context) {
	phone := ctx.PostForm("telephone")
	logger.Info("GetAuthCodeRequest req:", "phone:", phone)

	//判断手机号是否正确
	res := VerifyMobileFormat(phone)
	if res == false { //如果错误,则返回:手机号错误信息
		apicommon.ReturnErrorResponse(ctx, "手机号错误!", -1, "Wrong phone number")

	} else { //如果正确,则发送验证码给用户,并将验证码set到redis中
		//生成6位数随机验证码
		auth_code := fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
		//调用短信服务商,发送短信,此处代码暂时省略
		fmt.Println(auth_code)

		//将手机号及验证码set到redis中,过期时间为30s
		redis.RedisDB.Set(phone, auth_code, 30*time.Second)
		apicommon.ReturnSuccessResponse(ct "success", 0, nil)
	}
}

经过编译及运行以上代码后,进行测试和验证

# curl --location --request POST 'localhost:9100/api/v2/sso/getAuthCode' \
--form 'telephone="11081719844"'

{
    "message": "手机号错误!",
    "code": -1,
    "result": "Wrong phone number"
}

因为传入的手机号码错误,所以报错:手机号错误

# curl --location --request POST 'localhost:9100/api/v2/sso/getAuthCode' \
--form 'telephone="18281981546"'

{
    "message": "success",
    "code": 0,
    "result": "nil"
}

如果验证手机号码通过,则会返回成功的 message: success和code: 0 和result: nil。

如果 API 是对外的,错误信息数量有限,则制定错误码非常容易,强烈建议使用错误码。如果是内部系统,特别是庞大的系统,内部错误会非常多,这时候没必要为每一个错误制定错误码,而只需为常见的错误制定错误码,对于普通的错误,系统在处理时会统一作为 InternalServerError 处理。


本系列文章:
从零开发区块链应用(一)--golang配置文件管理工具viper
从零开发区块链应用(二)--mysql安装及数据库表的安装创建
从零开发区块链应用(三)--mysql初始化及gorm框架使用
从零开发区块链应用(四)--自定义业务错误信息



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK