关于golang:企业项目迁移gozero全攻略二

41次阅读

共计 3927 个字符,预计需要花费 10 分钟才能阅读完成。

承接上篇:上篇文章讲到 go-zero 架构设计和我的项目设计。本篇文章接着这个我的项目设计,将生成的 app 模块gatewayRPC 进行革新。废话不多说,让咱们开始!

gateway service

gateway 中我做了一些自定义,在端申请咱们后盾接口状况下,尽管少数状况是不须要关怀错误码的,然而防止不了要某些场景还是须要依据固定错误码去做非凡解决,我本人定义了一个谬误类,这个谬误类只在 gateway 中应用:

err.go:

package xerr

import "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 xerr

var message map[int]string

func 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 = 100001
const REUQES_PARAM_ERROR = 100002

// 用户模块
const USER_NOT_FOUND = 200001

我将三个文件对立放在 lib/xerr 目录

有了错误码还不行,还要定义对立返回 http 的后果,goctl 生成的默认的是挺好的,然而没法合乎我这种返回自定义错误码需要,于是我本人有写了一个对立返回后果的文件:

httpresult:

package xhttp

import (
   "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 xhttp

type (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 生成的代码:

当然你会说,每次生成完都要手动去改,好麻烦!

当当当当~~~ goctltemplate 来咯 https://www.yuque.com/tal-tec…

而后批改 ~/.goctl/api/handler.tpl:

package handler

import (
     "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 就是做这个,做链路追踪有很多,比方 jaegerzipkin

RPC service

modelrpc 服务中,官网文档举荐是将 model 放在 services 目录下,与每个 rpc 服务一层,然而个人感觉每个 model 对应一张表,一张表只能由一个服务去管制,哪个服务管制这张表就哪个服务领有管制这个 model 权力,其余服务想拜访就要通过 grpc,这是集体的想法,所以我把每个服务本人管控的 model 放在了 internal

enum:另外我在服务下加了 enum 枚举目录,因为其余 rpc 服务或者 api 服务会调用这个枚举去比对,我就放在 internal 内部

框架地址

https://github.com/tal-tech/go-zero

欢送应用 go-zerostar 反对咱们 ????


我为大家整顿了 go-zero 作者去年广受好评的分享视频,具体分享了 go-zero 的设计理念和最佳实际。关注公众号「微服务实际」,回复 视频 获取;还能够回复 进群 和数千 go-zero 使用者交流学习。

go-zero 系列文章见『微服务实际』公众号

正文完
 0