承接上篇:上篇文章讲到 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. 个人微信公众号搭建Python实现 -个人公众号搭建-总结(14.3.6)

    @ 目录 1.主要技术:Flask,requests 2.实现的主要功能 3.目录说明 4.运行方式 关于作者 1.主要技术:Flask,requests requirements.txt如下 req ...

  2. 用Python从头开始构建神经网络

    神经网络已经被开发用来模拟人脑.虽然我们还没有做到这一点,但神经网络在机器学习方面是非常有效的.它在上世纪80年代和90年代很流行,最近越来越流行.计算机的速度足以在合理的时间内运行一个大型神经网络. ...

  3. Python 写了一个批量生成文件夹和批量重命名的工具

    Python 写了一个批量生成文件夹和批量重命名的工具 目录 Python 写了一个批量生成文件夹和批量重命名的工具 演示 功能 1. 可以读取excel内容,使用excel单元格内容进行新建文件夹, ...

  4. Git提交错了不用慌,这三招帮你修改记录

    大家好,今天我们来聊聊git当中一个很重要的功能--历史记录的修改. 有的时候我们会突然发现某个地方需要修改,最常见的某个不应该被提交的文件被提交了进来.我们希望它不只是在后序的版本当中不再出现,而是 ...

  5. 【linux】系统编程-1-进程、管道和信号

    目录 1. 进程 1.1 概念 1.2 查看进程 1.3 启动新进程 1.3.1 system() 函数 1.3.2 fork() 函数 1.3.2 exce 系列函数 1.3.2.1 exce 系列 ...

  6. 关于线程池(ThreadPoolExecutor)参数的浅析

    引子 线程池在项目中很常用,需要多个任务异步执行的地方我们都会去创建一个线程池. 我们看到 ThreadPoolExecutor源码中提供了更方便的工厂方法(Executors)使用. 提供方便应该是 ...

  7. SQL语句中case,when,then的用法

    用法如下bai: 复制代码 SELECT s.s_id, s.s_name, s.s_sex, CASE WHENs.s_sex='1'THEN'男' WHENs.s_sex='2'THEN'女' E ...

  8. Could not open ServletContext resource [/WEB-INF/applicationContext.xml] 解决办法

    Spring官方文档中规定,如果在上下文中没有指定contextConfigLoction配置文件的位置,则会默认去WEB-INF中去寻找对应的配置文件. 理论上classpath的默认路径是WEB- ...

  9. 盘点 Java 开发 2020 年发生的几件大事,你必须得知道!

    2021 年了,在过去的一年 Java 软件开发行业都发生了哪些重大事件呢? 这篇栈长带大家回顾一下,其实在元旦的<滚蛋吧,2020>也略有介绍,这篇就更加详细的总结一下. 1.Java ...

  10. ROS开源小车TurtleBot3详情介绍

    您为什么要选择ROS开源智能小车 ROS(Robot Operating System,机器人操作系统)是目前世界上更主流更多人使用的的机器人开源操作系统.它可以提供操作系统应有的服务,包括硬件抽象, ...