go-zero返回值处理

使用go-zero框架的时候,发现在API请求过程中如果出现错误,接口会直接返回http400错误。这对前端或者其它服务端很不友好,他们需要获得详细错误信息,并且不返回http错误。同时,对于有错误的请求和成功的请求,接口返回的数据不一致。

总的来说,我们需要解决以下三个问题:

处理框架自带参数解析失败后产生的error(需自己处理)

处理逻辑层处理失败后产生的error(官方已处理)

修改模板,统一接口返回值(官方已处理)

后两个官方已处理,并加入官方学习文档,可自行查阅:

逻辑层错误官方解决方案:官方错误处理方法

统一接口返回值官方解决方案:官方统一请求返回方法

目前主要需要解决的就是框架自带的参数解析方法产生的错误,导致的http状态400问题,具体根据对应业务选择是否修改。我们以/num/add接口为例,一起学习一下整个修改过程,欢迎评论区交流~

根据官方文档自动生成接口项目代码

新建单个服务参考官方文档,单体服务创建

根据官方文档,一步一步操作就可以了。已经实践过的也可以直接下载源码进行修改,点击下载greet源码

新增一个post接口,实现两个整数相加的功能,核心代码如下:

修改greet.api文件,末尾添加如下代码:

type NumRequest {

FirstNum int `json:"first"`

SecondNum int `json:"second"`

}

type NumResponse {

Num int `json:"num"`

}

service greet-api {

@handler NumHandler

post /num/add(NumRequest) returns (NumResponse)

}

切换到greet根目录,使用goctl自动生成代码:

$ goctl api go -api greet.api -dir .

logic/numlogic.go 文件的Num方法内容修改如下:

func (l *NumLogic) Num(req types.NumRequest) (resp *types.NumResponse, err error) {

total := req.FirstNum + req.SecondNum

return &types.NumResponse{

Num: total,

}, nil

}

启动服务,命令如下:

$ go run greet.go

出现如下界面,服务启动成功:

Starting server at 0.0.0.0:8888...

接口调试

接口URL http://127.0.0.1:8888/num/add

正常情况请求正常情况返回

{

"first": 12,

"second": 223

}

异常情况请求异常情况返回400

{

"first2": 12,

"second": 223

}

代码修改

greet文件夹下新建目录/common/errorx,新建文件baseerror.go,用来处理error。

$ mkdir common&&cd common

$ mkdir errorx&&cd errorx

$ vim baseerror.go

通过实现error类型的Error方法,继承error类型,同时对CodeError并增加Data方法和NewSuccessJson统一返回结果

此处为了方便所有处理都放在这里,实际使用可根据情况分离成功和错误处理

此处为了方便所有处理都放在这里,实际使用可根据情况分离成功和错误处理

package errorx

const successCode = 0

const successMsg = "接口请求成功"

const defaultCode = 1001

const paramsFailedCode = 1002

type CodeError struct {

Code int `json:"code"`

Msg string `json:"msg"`

}

// CodeErrorResponse 此处结构体用于统一返回结果

type CodeErrorResponse struct {

Code int `json:"code"`

Msg string `json:"msg"`

Data interface{} `json:"data"`

}

func NewCodeError(code int, msg string) error {

return &CodeError{Code: code, Msg: msg}

}

// NewDefaultError 设置默认错误码

func NewDefaultError(msg string) error {

return NewCodeError(defaultCode, msg)

}

// NewParamsFailedError 设置接口参数json校验错误码

func NewParamsFailedError(msg string) error {

return NewCodeError(paramsFailedCode, msg)

}

func (e *CodeError) Error() string {

return e.Msg

}

// Data /**返回通用错误数据结构

func (e *CodeError) Data() *CodeErrorResponse {

return &CodeErrorResponse{

Code: e.Code,

Msg: e.Msg,

}

}

//NewSuccessJson /**接口请求成功返回数据

func NewSuccessJson(resp interface{}) *CodeErrorResponse {

return &CodeErrorResponse{

Code: successCode,

Msg: successMsg,

Data: resp,

}

}

修改handler层numhandler.go的NumHandler方法,处理json解析、逻辑层错误和正确的返回结果。注释部分为之前代码

func NumHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {

return func(w http.ResponseWriter, r *http.Request) {

var req types.NumRequest

if err := httpx.Parse(r, &req); err != nil {

//httpx.Error(w, err)

httpx.Error(w, errorx.NewParamsFailedError(err.Error()))

return

}

l := logic.NewNumLogic(r.Context(), svcCtx)

resp, err := l.Num(req)

if err != nil {

httpx.Error(w, err)

} else {

//httpx.OkJson(w, resp)

httpx.OkJson(w, errorx.NewSuccessJson(resp))

}

}

}

修改逻辑层numlogic.go文件Num方法返回的error,添加代码,当第一个数小于0返回错误:

func (l *NumLogic) Num(req types.NumRequest) (resp *types.NumResponse, err error) {

//此处为新增代码

if req.FirstNum < 0{

return nil, errorx.NewCodeError(1003, "第一个参数不允许小于0")

}

//此处新增结束

total := req.FirstNum + req.SecondNum

return &types.NumResponse{

Num: total,

}, nil

}

通过判断当前返回的error是自定义CodeError还是系统error,在greet.go中添加代码:

handler.RegisterHandlers(server, ctx)

// 此处为添加代码,当错误类型为自定义错误时,返回统一格式

httpx.SetErrorHandler(func(err error) (int, interface{}) {

switch e := err.(type) {

case *errorx.CodeError:

return http.StatusOK, e.Data()

default:

return http.StatusInternalServerError, nil

}

})

//此处添加结束

fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)

server.Start()

再次测试

正常情况请求

请求参数返回结果

{

"first": 12,

"second": 223

}

参数key错误情况请求(其它json解析错误可自己尝试,例如参数值类型错误)

请求参数返回结果

{

"first2": 12,

"second": 223

}

逻辑错误情况请求(其它可自己尝试,当前设置为第一个参数小于0)

请求参数返回结果

{

"first": -12,

"second": 223

}

可以看到,错误请求也都会返回相同的数据结构,代码添加成功。

修改模板

如果使用上述方法修改,对于自动生成的handler文件每次都要修改,这样就太麻烦,我们需要直接修改生成的模板。

按照官方文档一步步操作即可,点击查看官方自定义模板

此为我的修改过程

初始化模板(已初始化的跳过此步骤)

$ goctl template init

找到handler模板文件开始修改

$ vim ~/.goctl/1.3.2/api/handler.tpl

修改代码关键部分

修改前代码修改后代码

package {{.PkgName}}

import (

"net/http"

{{if .After1_1_10}}"github.com/zeromicro/go-zero/rest/httpx"{{end}}

{{.ImportPackages}}

)

func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {

return func(w http.ResponseWriter, r *http.Request) {

{{if .HasRequest}}var req types.{{.RequestType}}

if err := httpx.Parse(r, &req); err != nil {

httpx.Error(w, err)

return

}

{{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)

{{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}req{{end}})

if err != nil {

httpx.Error(w, err)

} else {

{{if .HasResp}}httpx.OkJson(w, resp){{else}}httpx.Ok(w){{end}}

}

}

}

修改完成之后,在greet.api文件新增一个接口,使用goctl自动生成代码,测试通过

总结

因为接口返回参数的问题,我们详细了解了go-zero框架中参数json解析错误、逻辑层错误处理、接口返回值统一处理问题。

在实际使用过程中,还需要根据具体情况分析处理,切忌死板硬套。

如果有更好的方法或想法也请大家多多指教~

你可能感兴趣的:(golang,golang)