经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
企业项目迁移go-zero全攻略(二)
来源:cnblogs  作者:Kevin Wan  时间:2021/1/25 11:15:02  对本文有异议

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

gateway service

gateway 中我做了一些自定义,在端请求我们后台接口情况下,虽然多数情况是不需要关心错误码的,但是避免不了要某些场景还是需要根据固定错误码去做特殊处理,我自己定义了一个错误类,这个错误类只在 gateway 中使用:

err.go:

  1. package xerr
  2. import "fmt"
  3. type CodeError struct {
  4. errCode int
  5. errMsg string
  6. }
  7. // 属性
  8. func (e *CodeError) GetErrCode() int {
  9. return e.errCode
  10. }
  11. func (e *CodeError) GetErrMsg() string {
  12. return e.errMsg
  13. }
  14. func (e *CodeError) Error() string {
  15. return fmt.Sprintf("ErrCode:%d,ErrMsg:%s", e.errCode, e.errMsg)
  16. }
  17. func New(errCode int, errMsg string) *CodeError {
  18. return &CodeError{errCode: errCode, errMsg: errMsg}
  19. }
  20. func NewErrCode(errCode int) *CodeError {
  21. return &CodeError{errCode: errCode, errMsg: MapErrMsg(errCode)}
  22. }
  23. func NewErrMsg(errMsg string) *CodeError {
  24. return &CodeError{errCode: BAD_REUQEST_ERROR, errMsg: errMsg}
  25. }

errmsg.go

  1. package xerr
  2. var message map[int]string
  3. func init() {
  4. message = make(map[int]string)
  5. message[OK] = "SUCCESS"
  6. message[BAD_REUQEST_ERROR] = "服务器繁忙,请稍后再试"
  7. message[REUQES_PARAM_ERROR] = "参数错误"
  8. message[USER_NOT_FOUND] = "用户不存在"
  9. }
  10. func MapErrMsg(errcode int) string {
  11. if msg, ok := message[errcode]; ok {
  12. return msg
  13. } else {
  14. return "服务器繁忙,请稍后再试"
  15. }
  16. }

errcode.go

  1. package xerr
  2. // 成功返回
  3. const OK = 200
  4. // 全局错误码
  5. // 前3位代表业务,后三位代表具体功能
  6. const BAD_REUQEST_ERROR = 100001
  7. const REUQES_PARAM_ERROR = 100002
  8. // 用户模块
  9. const USER_NOT_FOUND = 200001

我将三个文件统一放在 lib/xerr 目录

有了错误码还不行,还要定义统一返回http的结果,goctl 生成的默认的是挺好的,但是没法符合我这种返回自定义错误码需求,于是我自己有写了一个统一返回结果的文件:

httpresult:

  1. package xhttp
  2. import (
  3. "fishtwo/lib/xerr"
  4. "fmt"
  5. "github.com/tal-tech/go-zero/core/logx"
  6. "github.com/tal-tech/go-zero/rest/httpx"
  7. "google.golang.org/grpc/status"
  8. "net/http"
  9. "github.com/pkg/errors"
  10. )
  11. // http方法
  12. func HttpResult(r *http.Request,w http.ResponseWriter,resp interface{},err error) {
  13. if err == nil {
  14. // 成功返回
  15. r:= Success(resp)
  16. httpx.WriteJson(w, http.StatusOK, r)
  17. } else {
  18. // 错误返回
  19. errcode := xerr.BAD_REUQEST_ERROR
  20. errmsg := "服务器繁忙,请稍后再试"
  21. if e,ok := err.(*xerr.CodeError);ok{
  22. // 自定义CodeError
  23. errcode = e.GetErrCode()
  24. errmsg = e.GetErrMsg()
  25. } else {
  26. originErr := errors.Cause(err) // err类型
  27. if gstatus, ok := status.FromError(originErr);ok{
  28. // grpc err错误
  29. errmsg = gstatus.Message()
  30. }
  31. }
  32. logx.WithContext(r.Context()).Error("【GATEWAY-SRV-ERR】 : %+v ",err)
  33. httpx.WriteJson(w, http.StatusBadRequest, Error(errcode,errmsg))
  34. }
  35. }
  36. // http参数错误返回
  37. func ParamErrorResult(r *http.Request,w http.ResponseWriter,err error) {
  38. errMsg := fmt.Sprintf("%s ,%s", xerr.MapErrMsg(xerr.REUQES_PARAM_ERROR), err.Error())
  39. httpx.WriteJson(w, http.StatusBadRequest, Error(xerr.REUQES_PARAM_ERROR,errMsg))
  40. }

responsebean

  1. package xhttp
  2. type (
  3. NullJson struct {}
  4. ResponseSuccessBean struct {
  5. Code int `json:"code"`
  6. Msg string `json:"msg"`
  7. Data interface{} `json:"data"`
  8. }
  9. )
  10. func Success(data interface{}) *ResponseSuccessBean {
  11. return &ResponseSuccessBean{200, "OK", data}
  12. }
  13. type ResponseErrorBean struct {
  14. Code int `json:"code"`
  15. Msg string `json:"msg"`
  16. }
  17. func Error(errCode int,errMsg string) *ResponseErrorBean {
  18. return &ResponseErrorBean{errCode, errMsg}
  19. }

放在 lib/xhttp下

然后改造了internal/handler/下通过goctl生成的代码:

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

当当当当~~~ goctltemplate 来咯 https://www.yuque.com/tal-tech/go-zero/mkpuit

然后修改 ~/.goctl/api/handler.tpl:

  1. package handler
  2. import (
  3. "net/http"
  4. {{.ImportPackages}}
  5. )
  6. func {{.HandlerName}}(ctx *svc.ServiceContext) http.HandlerFunc {
  7. return func(w http.ResponseWriter, r *http.Request) {
  8. {{if .HasRequest}}var req types.{{.RequestType}}
  9. if err := httpx.Parse(r, &req); err != nil {
  10. xhttp.ParamErrorResult(r,w,err)
  11. return
  12. }{{end}}
  13. l := logic.New{{.LogicType}}(r.Context(), ctx)
  14. resp, err := l.Login(req)
  15. xhttp.HttpResult(r,w,resp,err)
  16. }
  17. }

再重新生成看看,是不是就 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 系列文章见『微服务实践』公众号

原文链接:http://www.cnblogs.com/kevinwan/p/14323635.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号