承接上篇:上篇文章讲到 go-zero
架构设计和我的项目设计。本篇文章接着这个我的项目设计,将生成的 app 模块
中 gateway
和 RPC
进行革新。废话不多说,让咱们开始!
gateway service
gateway 中我做了一些自定义,在端申请咱们后盾接口状况下,尽管少数状况是不须要关怀错误码的,然而防止不了要某些场景还是须要依据固定错误码去做非凡解决,我本人定义了一个谬误类,这个谬误类只在 gateway 中应用:
err.go:
package xerrimport "fmt"type CodeError struct { errCode int errMsg string}// 属性func (e *CodeError) GetErrCode() int { return e.errCode}func (e *CodeError) GetErrMsg() string { return e.errMsg}func (e *CodeError) Error() string { return fmt.Sprintf("ErrCode:%d,ErrMsg:%s", e.errCode, e.errMsg)}func New(errCode int, errMsg string) *CodeError { return &CodeError{errCode: errCode, errMsg: errMsg}}func NewErrCode(errCode int) *CodeError { return &CodeError{errCode: errCode, errMsg: MapErrMsg(errCode)}}func NewErrMsg(errMsg string) *CodeError { return &CodeError{errCode: BAD_REUQEST_ERROR, errMsg: errMsg}}
errmsg.go
package xerrvar message map[int]stringfunc init() { message = make(map[int]string) message[OK] = "SUCCESS" message[BAD_REUQEST_ERROR] = "服务器忙碌,请稍后再试" message[REUQES_PARAM_ERROR] = "参数谬误" message[USER_NOT_FOUND] = "用户不存在"}func MapErrMsg(errcode int) string { if msg, ok := message[errcode]; ok { return msg } else { return "服务器忙碌,请稍后再试" }}
errcode.go
package xerr// 胜利返回const OK = 200// 全局错误码// 前3位代表业务,后三位代表具体性能const BAD_REUQEST_ERROR = 100001const REUQES_PARAM_ERROR = 100002// 用户模块const USER_NOT_FOUND = 200001
我将三个文件对立放在 lib/xerr
目录
有了错误码还不行,还要定义对立返回http的后果,goctl
生成的默认的是挺好的,然而没法合乎我这种返回自定义错误码需要,于是我本人有写了一个对立返回后果的文件:
httpresult:
package xhttpimport ( "fishtwo/lib/xerr" "fmt" "github.com/tal-tech/go-zero/core/logx" "github.com/tal-tech/go-zero/rest/httpx" "google.golang.org/grpc/status" "net/http" "github.com/pkg/errors")// http办法func HttpResult(r *http.Request,w http.ResponseWriter,resp interface{},err error) { if err == nil { // 胜利返回 r:= Success(resp) httpx.WriteJson(w, http.StatusOK, r) } else { // 谬误返回 errcode := xerr.BAD_REUQEST_ERROR errmsg := "服务器忙碌,请稍后再试" if e,ok := err.(*xerr.CodeError);ok{ // 自定义CodeError errcode = e.GetErrCode() errmsg = e.GetErrMsg() } else { originErr := errors.Cause(err) // err类型 if gstatus, ok := status.FromError(originErr);ok{ // grpc err谬误 errmsg = gstatus.Message() } } logx.WithContext(r.Context()).Error("【GATEWAY-SRV-ERR】 : %+v ",err) httpx.WriteJson(w, http.StatusBadRequest, Error(errcode,errmsg)) }}// http参数谬误返回func ParamErrorResult(r *http.Request,w http.ResponseWriter,err error) { errMsg := fmt.Sprintf("%s ,%s", xerr.MapErrMsg(xerr.REUQES_PARAM_ERROR), err.Error()) httpx.WriteJson(w, http.StatusBadRequest, Error(xerr.REUQES_PARAM_ERROR,errMsg))}
responsebean
package xhttptype ( NullJson struct {} ResponseSuccessBean struct { Code int `json:"code"` Msg string `json:"msg"` Data interface{} `json:"data"` })func Success(data interface{}) *ResponseSuccessBean { return &ResponseSuccessBean{200, "OK", data}}type ResponseErrorBean struct { Code int `json:"code"` Msg string `json:"msg"`}func Error(errCode int,errMsg string) *ResponseErrorBean { return &ResponseErrorBean{errCode, errMsg}}
放在 lib/xhttp下
而后革新了internal/handler/下通过goctl生成的代码:
当然你会说,每次生成完都要手动去改,好麻烦!
当当当当~~~ goctl
的 template
来咯 https://www.yuque.com/tal-tec...
而后批改 ~/.goctl/api/handler.tpl
:
package handlerimport ( "net/http" {{.ImportPackages}})func {{.HandlerName}}(ctx *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 { xhttp.ParamErrorResult(r,w,err) return }{{end}} l := logic.New{{.LogicType}}(r.Context(), ctx) resp, err := l.Login(req) xhttp.HttpResult(r,w,resp,err) }}
再从新生成看看,是不是就 beautiful
了,哈哈
而后在说咱们的 gateway log
,如果眼神好的用户,在下面的 httpresult.go
中曾经看到了 log
的身影:
是的是的,这样解决就能够啦,这样只有有谬误就会打印日志了,go-zero
曾经把 trace-id
带进去了,啥?trace-id
不晓得是啥?嗯,其实就是把一次申请通过此 id
串联起来,比方你 user-api
调用 user->srv
或者其余 srv
,那要把他们这一次申请都串联起来,须要一个惟一标识别,这个 id
就是做这个,做链路追踪有很多,比方 jaeger
、zipkin
。
RPC service
model
:rpc
服务中,官网文档举荐是将 model
放在 services
目录下,与每个 rpc
服务一层,然而个人感觉每个 model
对应一张表,一张表只能由一个服务去管制,哪个服务管制这张表就哪个服务领有管制这个 model
权力,其余服务想拜访就要通过 grpc
,这是集体的想法,所以我把每个服务本人管控的 model
放在了 internal
中
enum
:另外我在服务下加了 enum
枚举目录,因为其余 rpc
服务或者 api
服务会调用这个枚举去比对,我就放在 internal
内部
框架地址
https://github.com/tal-tech/go-zero
欢送应用 go-zero
并 star 反对咱们 ????
我为大家整顿了 go-zero 作者去年广受好评的分享视频,具体分享了 go-zero 的设计理念和最佳实际。关注公众号「微服务实际」,回复 视频 获取;还能够回复 进群 和数千 go-zero 使用者交流学习。
go-zero 系列文章见『微服务实际』公众号