企业项目迁移go-zero实战(二)

简介: 企业项目迁移go-zero实战(二)

承接上篇:上篇文章讲到 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-tech/go-zero/mkpuit

然后修改 ~/.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

相关文章
|
1月前
|
人工智能 安全 算法
Go入门实战:并发模式的使用
本文详细探讨了Go语言的并发模式,包括Goroutine、Channel、Mutex和WaitGroup等核心概念。通过具体代码实例与详细解释,介绍了这些模式的原理及应用。同时分析了未来发展趋势与挑战,如更高效的并发控制、更好的并发安全及性能优化。Go语言凭借其优秀的并发性能,在现代编程中备受青睐。
103 33
|
20天前
|
Go
【LeetCode 热题100】DP 实战进阶:最长递增子序列、乘积最大子数组、分割等和子集(力扣300 / 152/ 416 )(Go语言版)
本文深入解析三道经典的动态规划问题:**最长递增子序列(LIS)**、**乘积最大子数组** 和 **分割等和子集**。 - **300. LIS** 通过 `dp[i]` 表示以第 `i` 个元素结尾的最长递增子序列长度,支持 O(n²) 动态规划与 O(n log n) 的二分优化。 - **152. 乘积最大子数组** 利用正负数特性,同时维护最大值与最小值的状态转移方程。 - **416. 分割等和子集** 转化为 0-1 背包问题,通过布尔型 DP 实现子集和判断。 总结对比了三题的状态定义与解法技巧,并延伸至相关变种问题,助你掌握动态规划的核心思想与灵活应用!
45 1
|
20天前
|
分布式计算 算法 Go
【LeetCode 热题100】BFS/DFS 实战:岛屿数量 & 腐烂的橘子(力扣200 / 994 )(Go语言版)
本文讲解了两道经典的图论问题:**岛屿数量(LeetCode 200)** 和 **腐烂的橘子(LeetCode 994)**,分别通过 DFS/BFS 实现。在“岛屿数量”中,利用深度或广度优先搜索遍历二维网格,标记连通陆地并计数;“腐烂的橘子”则采用多源 BFS,模拟腐烂传播过程,计算最短时间。两者均需掌握访问标记技巧,是学习网格搜索算法的绝佳实践。
49 1
|
20天前
|
Go
【LeetCode 热题100】BFS/DFS 实战:岛屿数量 & 腐烂的橘子(力扣200 / 994 )(Go语言版)
本篇博客详细解析了三道经典的动态规划问题:198. 打家劫舍(线性状态转移)、279. 完全平方数与322. 零钱兑换(完全背包问题)。通过 Go 语言实现,帮助读者掌握动态规划的核心思想及其实战技巧。从状态定义到转移方程,逐步剖析每道题的解法,并总结其异同点,助力解决更复杂的 DP 问题。适合初学者深入理解动态规划的应用场景和优化方法。
36 0
|
2月前
|
Go API 定位技术
MCP 实战:用 Go 语言开发一个查询 IP 信息的 MCP 服务器
随着 MCP 的快速普及和广泛应用,MCP 服务器也层出不穷。大多数开发者使用的 MCP 服务器开发库是官方提供的 typescript-sdk,而作为 Go 开发者,我们也可以借助优秀的第三方库去开发 MCP 服务器,例如 ThinkInAIXYZ/go-mcp。 本文将详细介绍如何在 Go 语言中使用 go-mcp 库来开发一个查询 IP 信息的 MCP 服务器。
142 0
|
4月前
|
存储 缓存 监控
企业监控软件中 Go 语言哈希表算法的应用研究与分析
在数字化时代,企业监控软件对企业的稳定运营至关重要。哈希表(散列表)作为高效的数据结构,广泛应用于企业监控中,如设备状态管理、数据分类和缓存机制。Go 语言中的 map 实现了哈希表,能快速处理海量监控数据,确保实时准确反映设备状态,提升系统性能,助力企业实现智能化管理。
74 3
|
4月前
|
存储 算法 Go
Go语言实战:错误处理和panic_recover之自定义错误类型
本文深入探讨了Go语言中的错误处理和panic/recover机制,涵盖错误处理的基本概念、自定义错误类型的定义、panic和recover的工作原理及应用场景。通过具体代码示例介绍了如何定义自定义错误类型、检查和处理错误值,并使用panic和recover处理运行时错误。文章还讨论了错误处理在实际开发中的应用,如网络编程、文件操作和并发编程,并推荐了一些学习资源。最后展望了未来Go语言在错误处理方面的优化方向。
|
6月前
|
监控 算法 安全
解锁企业计算机监控的关键:基于 Go 语言的精准洞察算法
企业计算机监控在数字化浪潮下至关重要,旨在保障信息资产安全与高效运营。利用Go语言的并发编程和系统交互能力,通过进程监控、网络行为分析及应用程序使用记录等手段,实时掌握计算机运行状态。具体实现包括获取进程信息、解析网络数据包、记录应用使用时长等,确保企业信息安全合规,提升工作效率。本文转载自:[VIPShare](https://www.vipshare.com)。
77 1
|
7月前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
661 4
|
7月前
|
存储 JSON Go
如何在 Go 项目中隐藏敏感信息,比如避免暴露用户密码?
在Go语言开发中,用户信息管理常涉及敏感数据如密码的处理。为防止这些数据暴露给客户端,本文介绍了三种方法:使用JSON标签忽略字段、自定义序列化逻辑、使用数据传输对象(DTO),以确保用户数据的安全性。通过这些方法,可以有效控制数据输出,避免敏感信息泄露。
120 1