承接上篇:上篇文章讲到 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

欢迎使用 go-zerostar 支持我们


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

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

企业项目迁移go-zero全攻略(二)的更多相关文章

  1. 废弃fastjson!大型项目迁移Gson保姆级攻略

    前言 大家好,又双叒叕见面了,我是天天放大家鸽子的蛮三刀. 在被大家取关之前,我立下一个"远大的理想",一定要在这周更新文章.现在看来,flag有用了... 本篇文章是我这一个多月 ...

  2. 打造一个高逼格的android开源项目——小白全攻略 (转)

    转自:打造一个高逼格的android开源项目 小引子 在平时的开发过程中,我们经常会查阅很多的资料,最常参考的是 github 的开源项目.通常在项目的主页面能看到项目的简介和基本使用,并且时不时能看 ...

  3. Moon.Orm3.8技术全攻略

    Moon.ORM技术全攻略  一.绪论 本文主要是针对Moon.ORM的技术的讨论及其使用使用指导.如有其它疑问,请留言.本文主要针对Moon.ORM3.9版本,同时将会对4.0做一个技术预览.本文从 ...

  4. 生成 PDF 全攻略【2】在已有PDF上添加内容

    项目在变,需求在变,不变的永远是敲击键盘的程序员..... PDF 生成后,有时候需要在PDF上面添加一些其他的内容,比如文字,图片.... 经历几次失败的尝试,终于获取到了正确的代码书写方式. 在此 ...

  5. 从小工到专家 ——读《Java程序员职场全攻略》有感

    从小工到专家 ——读<Java程序员职场全攻略>有感   <Java程序员职场全攻略>是以故事的形式,向读者介绍Java程序员的职场经验.作者牛开复在北京从事软件开发,已经是一 ...

  6. 用C#制作PDF文件全攻略

    用C#制作PDF文件全攻略 目  录 前    言... 3 第一部分 iText的简单应用... 4 第一章 创建一个Document 4 第一步 创建一个Document实例:... 5 第二步 ...

  7. (转)战斗bug技巧全攻略

    原文地址:http://www.cnblogs.com/manuosex/p/3736077.html 程序员不是有一幅这样的对联吗 上联:一个项目两部电脑三餐盒饭只为四千工资搞得五脏俱损六神无主仍然 ...

  8. Android-x86虚拟机安装配置全攻略

    转自Android-x86虚拟机安装配置全攻略 注:这里安装从简,具体请参考虚拟机Vmware安装运行安卓4.0详细教程 Android-x86虚拟机安装配置网上有很多,但是全部说明白的确不多,希望这 ...

  9. [置顶] 创建GitHub技术博客全攻略

    [置顶] 创建GitHub技术博客全攻略 分类: GitHub2014-07-12 13:10 19710人阅读 评论(21) 收藏 举报 githubio技术博客网站生成 说明: 首先,你需要注册一 ...

  10. Android使用XML全攻略(1)

    Android使用XML全攻略(1)    Android 是针对移动设备的一种新兴的开源操作系统和 SDK.借助它,您可以创建功能强大的移动应用程序.当您的应用程序可以访问 Web 服务时,其吸引力 ...

随机推荐

  1. C# 将json字符串进行排序 转成键值

    public static string StortJson(string json) { var dic = JsonConvert.DeserializeObject<SortedDicti ...

  2. asp.net mvc ajax文件上传

    前台页面提交文件 <!DOCTYPE html> <html> <head> <meta name="viewport" content= ...

  3. MVC中Bundle的使用

    BundleConfig配置 (1)StyleBundle中的参数,即为cshtml中需要调用的虚拟路径名称. (2)Include包含路径,可以包含一个或多个css或js文件.即包含一组文件. pu ...

  4. 浅谈 WebRTC 的 Audio 在进入 Encoder 之前的处理流程

    在 WebRTC 中,Audio 数据在被送入编码器之前,有 2 大部分需要特别关注,一是数据采集,二是 Audio Processing. 作者:方来,技术专家,从事 voip 应用开发. 数据采集 ...

  5. Spring Boot 中使用 Quartz 实现任务调度

    Quartz 概述 Quartz 是 OpenSymphony 开源组织在 Job Scheduling 领域又一个开源项目,它可以与 J2EE. J2SE 应用程序相结合也可以单独使用.Quartz ...

  6. 服务器运行jupyter,本地浏览器打开

    https://www.cnblogs.com/wwwhza/p/8821117.html https://blog.csdn.net/qq_29762941/article/details/8063 ...

  7. JavaWeb代码复用

    servlet部分,可能用得到的复用的代码: 1.dopost设置字符 request.setCharacterEncoding("utf-8"); response.setCha ...

  8. Centos7 安装Teamviewer

    参考:链接1  链接2  链接3 由于工作原因,需要再Centos7.6下安装Teamviewer,流程如下: 下载 TeamViewer下载 链接 wget https://download.tea ...

  9. 对于home主页的切换处理

    经过测试,发现,在home首页的时候,滑动到某一个位置的时候,如果再点击tabbar中的"购物车"."分类"或者"我的"的时候,再点击到首页 ...

  10. 线程上下文类加载器(Context ClassLoader)

    1.线程上下文类加载器是从jdk1.2开始引入的,类Thread中的getContextClassLoader()与setContextClassLoader(ClassLoader c1),分别用来 ...