一个go的支持多语言的error自动生成插件
大家好,我是peachesTao,今天给大家推荐一个go的支持多语言的error自动生成的插件,插件主页可以访问下方链接。
在一个多语言国际化的项目中,后端接口返回给前端的错误描述也需要国际化,我们来看一下后端给前端返回多语言错误描述的实现方式有哪些。
常规实现
服务端将错误码和不同语言的错误描述硬编码在代码中,通过前端从http head中传过来的language来决定是返回中文还是英文。
1、定义Error结构体
该结构体实现标准库的error接口,实现自定义error
type Error struct {Code intMsg string
}func (e *Error) Error() string {return fmt.Sprintf("%d,%s", e.Code, e.Msg)
}
2、定义错误码和错误描述map
const (Err_Code_Success = 0Err_Code_UnKnown = -1Err_Code_InValid_Phone = 10001
)const (Language_Chinese = 0 //中文Language_Enligh = 1 //英文
)//不同语言对应的错误描述
var errMap = map[int]map[int]string{Language_Chinese: {Err_Code_Success: "成功",Err_Code_InValid_Phone: "手机号格式不正确",Err_Code_UnKnown: "未知错误",},Language_Enligh: {Err_Code_Success: "success",Err_Code_InValid_Phone: "invalid phone no",Err_Code_UnKnown: "unknown err",},
}
3、申明一个用户注册的api
根据客户端传过来的http header中的language的值决定返回中文还是英文的错误描述
func main() {http.HandleFunc("/user/register", func(w http.ResponseWriter, r *http.Request) {languageStr := r.Header.Get("language")language, _ := strconv.Atoi(languageStr)values, _ := url.ParseQuery(r.URL.RawQuery)phone := values["phone"][0]err := checkPhone(phone)response(w, language, err)})http.ListenAndServe(":8080", nil)
}func response(w http.ResponseWriter, language int, err error) {e := &Error{Code: Err_Code_Success}if err != nil {var ok boolif e, ok = err.(*Error); !ok {e = &Error{Code: Err_Code_UnKnown}}}msg := errMap[language][e.Code]res := make(map[string]interface{})res["code"] = e.Coderes["msg"] = msgjson, _ := json.Marshal(res)w.WriteHeader(200)w.Write(json)
}func checkPhone(phoneNo string) error {if len(phoneNo) != 11 {return &Error{Code: Err_Code_InValid_Phone}}return nil
}
我们通过curl命令来看看效果
语言设置为中文时:
curl -H "language:0" "http://127.0.0.1:8080/user/register?phone=187111111112"
{"code":10001,"msg":"手机号格式不正确"}
语言设置为英文时:
curl -H "language:1" "http://127.0.0.1:8080/user/register?phone=187111111112"
{"code":10001,"msg":"invalid phone no"}
这种实现方式确实能满足业务需求,但是有下面几个缺点:
- 当要将手机号格式不正确的描述改时需要修改代码
- 当添加新的错误时需要改动多个地方代码:添加新的错误码和在errMap中添加对应语言的错误描述,容易遗漏
- 当添加新的语言时要向errMap添加所有错误码的新语言错误描述,容易遗漏
一旦涉及到修改代码就存在出现bug的风险,有没有一种更优雅的方案,尽量减少修改代码?
有人会想到将错误描述放在json文件中维护,这种方案只是在修改错误描述时比较便利,不需要改动业务代码,但在新增错误和新语言时存在同样的问题。
下面我们来看看通过go-error-generator插件的方法来实现
更优雅的实现
go-error-generator是一个通过protobuf文件的Enum对象自动生成Error的插件,通过在扩展的EnumValueOptions中定义多个option轻松实现error的多语言。
它包含如下功能:
- 根据Enum定义的errCode和msg自动生成error;
- 支持定义多个EnumValueOption,实现多语言;
- 支持error合并功能;
- 支持自定义Error结构体、error Code和Msg的名称;
关于插件的原理和其他细节可以访问github主页了解。
我们回到刚才那个需求,用插件的方式怎么实现错误多语言
1、定义error模板
删除代码中的的Error结构体,取代的是在protobuf中定义,新建一个protobuf文件,取名为error.proto,在这里自定义error结构体和语言标识。
其中:
- msg:默认的语言标识,在错误码定义文件中没有定义其他语言的错误描述时就用它的错误描述
- msg_english:英文标识,当然你也可以取别的名字
syntax = "proto3";
package errors;
option go_package = "github.com/classtorch/go-error-generator-examples/internal/errors";
import "google/protobuf/descriptor.proto";message Error {int32 code = 1;string msg = 2;
};
extend google.protobuf.EnumValueOptions {string msg = 1108;string msg_english = 1109;
}
2、定义错误码和错误描述
新建一个protobuf文件,取名为account.proto
导入上面定义好的error.proto,自定义msg和msg_english对应的错误描述
syntax = "proto3";
package uclass.service.account;
option go_package = "/golang/account";
import "errors/errors.proto";enum ErrorCode {SUCCESS = 0 [(errors.msg) = "成功", (errors.msg_english) = "success"]; // 成功UnKnown = -1 [(errors.msg) = "未知错误", (errors.msg_english) = "unknown err"]; // 账号不存在InValid_Phone = 10001 [(errors.msg) = "手机号格式不正确", (errors.msg_english) = "invalid phone no"]; // 登录失效,请重新登录
}
3、通过插件生成代码
该插件需要安装go和protobuf运行环境
- go
- protoc
- protoc-gen-go
安装好运行环境后再安装go-error-generator插件
go install github.com/classtorch/go-error-generator/protoc-gen-go-error-generator
安装好后执行下面脚本生成代码
protoc --go-error-generator_out=:. \--go-error-generator_opt descriptor_file=errors/errors.proto \--go-error-generator_opt merge_error=false \--go-error-generator_opt merge_error_path=golang/errors \--go_out=. -I . account.proto
插件自动生成的代码如下,包含error对象和error map
var (SUCCESS = &errors.Error{Code: 0, Msg: "成功"} //成功UnKnown = &errors.Error{Code: -1, Msg: "未知错误"} //未知错误InValid_Phone = &errors.Error{Code: 10001, Msg: "手机号格式不正确"} //手机号格式不正确
)var (Msg = map[int32]*errors.Error{0: &errors.Error{Code: 0, Msg: "成功"},-1: &errors.Error{Code: -1, Msg: "未知错误"},10001: &errors.Error{Code: 10001, Msg: "手机号格式不正确"},}Msg_English = map[int32]*errors.Error{0: &errors.Error{Code: 0, Msg: "success"},-1: &errors.Error{Code: -1, Msg: "unknown err"},10001: &errors.Error{Code: 10001, Msg: "invalid phone no"},}
)
4、使用生成的error对象
使用生成的error对象和error map改写response和checkPhone方法
func response(w http.ResponseWriter, language int, err error) {e := account.SUCCESSvar ok boolif err != nil {if e, ok = err.(*errors.Error); !ok {e = account.UnKnown}}if language == Language_Chinese {if e, ok = account.Msg[e.Code]; !ok {e = account.UnKnown}} else if language == Language_Enligh {if e, ok = account.Msg_English[e.Code]; !ok {e = account.UnKnown}}res := make(map[string]interface{})res["code"] = e.Coderes["msg"] = e.Msgjson, _ := json.Marshal(res)w.WriteHeader(200)w.Write(json)
}func checkPhone(phoneNo string) error {if len(phoneNo) != 11 {return account.InValid_Phone}return nil
}
完整的代码可以访问go-error-generator-examples项目进行了解
我们来看下这是实现方式的优点
- 当我们需要修改某个错误描述时直接在account.proto文件中修改,无须修改代码
- 当需要增加新的错误时直接在account.proto文件中定义,生成代码后直接在业务代码中引用即可
- 当添加新的语言时只需要在error.proto中增加新的语言标识即,然后在account.proto中引入即可
可以看出对于第一个和和第三个需求来说只需要修改protobuf文件,重新生成代码就可以,无须修改业务代码。第二个需求也只是简单的引入新的错误对象。
由于该插件是基于protobuf实现的,如果项目中没有使用prorobuf技术栈的话会带来一些引入成本。不过这点成本相对于频繁修改业务代码还是值得的。
相关链接
go-error-generator
go-error-generator-examples
相关文章:
![](https://www.ngui.cc/images/no-images.jpg)
一个go的支持多语言的error自动生成插件
大家好,我是peachesTao,今天给大家推荐一个go的支持多语言的error自动生成的插件,插件主页可以访问下方链接。 在一个多语言国际化的项目中,后端接口返回给前端的错误描述也需要国际化,我们来看一下后端给前端返回多语…...
![](https://img-blog.csdnimg.cn/079f0a6a7a604a308c564f41e454e34f.png)
wireshark抓包新手使用教程(超详细)
一、简介 Wireshark是一款非常流行的网络封包分析软件,可以截取各种网络数据包,并显示数据包详细信息。 为了安全考虑,wireshark只能查看封包,而不能修改封包的内容,或者发送封包。 wireshark能获取HTTP,也…...
![](https://img-blog.csdnimg.cn/eadf92906d584f7eb483c25b1e0db5aa.jpeg)
平均列顺序对列排斥能的影响
( A, B )---3*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有3个节点,AB训练集各由5张二值化的图片组成,让A有6个1,B有4个1,并且让这10个1的位置没有重合。比较迭代次数的顺序。 其中有9组数据 差值结构 A-B 迭代次数 构造平均列 …...
![](https://www.ngui.cc/images/no-images.jpg)
微信小程序-处理ios无法播放语音的问题
背景 框架:tarovue3 问题:今天搞小程序语音播放功能,开放工具播放正常,但是到ios手机上调试时无法播放,在网上找到个好办法 解决方案 核心代码 Taro.setInnerAudioOption({obeyMuteSwitch: false // 解决有一些IOS无…...
![](https://img-blog.csdnimg.cn/61632a02f5484c33bc6a12e221026f1f.png)
区块链 2.0笔记
区块链 2.0 以太坊概述 相对于比特币的几点改进 缩短出块时间至10多秒ghost共识机制mining puzzle BTC:计算密集型ETH:memory-hard(限制ASIC) proof of work->proof of stake对智能合约的支持 BTC:decentralized currencyETH:decentral…...
![](https://img-blog.csdnimg.cn/6e29286affb94acfb6308b1583f4da53.webp)
深入理解Vue响应式系统:数据绑定探索
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...
![](https://img-blog.csdnimg.cn/8e61b0b48dc148efb079035031dfed2c.jpg)
web流程自动化详解
今天给大家带来Selenium的相关解释操作 一、Selenium Selenium是一个用于自动化Web浏览器操作的开源工具和框架。它提供了一组API(应用程序接口),可以让开发人员使用多种编程语言(如Java、Python、C#等)编写测试脚本&…...
![](https://img-blog.csdnimg.cn/65e9ee3ba68d40449907a2e44308595f.png)
什么是框架?为什么要学框架?
一、什么是框架 框架是整个或部分应用的可重用设计,是可定制化的应用骨架。它可以帮开发人员简化开发过程,提高开发效率。 项目里有一部分代码:和业务无关,而又不得不写的代码>框架 项目里剩下的部分代码:实现业务…...
![](https://www.ngui.cc/images/no-images.jpg)
什么是 Sass?
Sass 介绍 什么是 Sass? 官方标语 世界上最成熟、最稳定、最强大的专业级 CSS 扩展语言。怎么理解这句话呢?我们平时写的 CSS 代码可以理解为静态样式语言,而 Scss 就是动态样式语言,何为动态?就是让你写 CSS 跟写 …...
![](https://img-blog.csdnimg.cn/fc5b35303fa04150b483aa7b7e6e9c9a.png#pic_center)
Kotlin~Memento备忘录模式
概念 备忘录模式是一种行为型设计模式,用于捕获和存储对象的内部状态,并在需要时将对象恢复到之前的状态。 备忘录模式允许在不暴露对象内部实现细节的情况下,对对象进行状态的保存和恢复。 角色介绍 Originator:原发器&#x…...
![](https://img-blog.csdnimg.cn/a19cf3bfa88e487bb085c66de6931203.png)
单链表的多语言表达:C++、Java、Python、Go、Rust
单链表 是一种链式数据结构,由一个头节点和一些指向下一个节点的指针组成。每个节点包含一个数据元素和指向下一个节点的指针。头节点没有数据,只用于表示链表的开始位置。 单链表的主要操作包括: 添加元素:在链表的头部添加新…...
![](https://www.ngui.cc/images/no-images.jpg)
微信小程序 background-image直接设置本地图片路径,编辑器正常显示,真机运行不显示解决方法
项目场景 微信小程序,设置background-image直接设置本地图片路径。 问题描述 编辑器正常显示,真机运行不显示 原因分析 background-image只能用网络url或者base64图片编码。 解决方案 1、将本地图片转为网络url后设置到background-image上 例如&…...
![](https://img-blog.csdnimg.cn/e7e5326423f4464b949165be43d5d940.png)
SQLite Studio 连接 SQLite数据库
1、在SQLite中创建数据库和表 1.1、按WINR,打开控制台,然后把指引到我们的SQLite的安装路径,输入D:,切换到D盘,cd 地址,切换到具体文件夹,输入“sqlite3”,启动服务 1.2、创建数据库…...
![](https://img-blog.csdnimg.cn/img_convert/082528a76b632fb017b38ab9aade2443.png)
【业务功能篇58】Springboot + Spring Security 权限管理 【中篇】
4.2.3 认证 4.2.3.1 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份,证明“你是你自己”(比如:你每天上下班打卡,都需要通过指纹打卡,当你的指纹和系统里录入的指纹相匹配时&…...
![](https://img-blog.csdnimg.cn/c6046c1b93ff4e02b73c56511b451271.png)
Docker挂载目录失败问题解决
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
![](https://www.ngui.cc/images/no-images.jpg)
css中隐藏页面中某一个元素有什么方法?
我们可以使用css的z-index属性,将元素的-index去给它设置一个负值,使它隐藏在其他元素的后面。使用css样式进行隐藏我们可以使用display这个属性。(1)使用display:none完全进行隐藏元素,并且不占据空间也不会影响页面布…...
![](https://www.ngui.cc/images/no-images.jpg)
Unity 多语言问题C#篇
DateTime.ToString()不同语言环境问题 问题描述:PlayerPrefs.SetString("timeKey", DateTime.Now.ToString());切换系统语言后DateTime.Parse(PlayerPrefs.GetString("timeKey"));报错FormatException: String was not recognized as a valid D…...
![](https://img-blog.csdnimg.cn/935070c2f0a54663baab64cff75b5495.png)
深度学习和神经网络
人工神经网络分为两个阶段: 1 :接收来自其他n个神经元传递过来的信号,这些输入信号通过与相应的权重进行 加权求和传递给下个阶段。(预激活阶段) 2:把预激活的加权结果传递给激活函数 sum :加权 f:激活…...
![](https://www.ngui.cc/images/no-images.jpg)
在CSDN学Golang云原生(Kubernetes Volume)
一,Volume 与 configMap Kubernetes 中的 Volume 和 ConfigMap 都是 Kubernetes 中常用的资源对象。它们可以为容器提供持久化存储和配置文件等。 Volume 可以将容器内部的文件系统挂载到宿主机上,也可以将多个容器间共享一个 Volume,并且 …...
![](https://www.ngui.cc/images/no-images.jpg)
第十五章 友元 异常和其他
RTTI RTTI是什么 RTTI是运行阶段类型识别,通过运行时类型识别,程序能够使用基类的指针或者引用来检查这些指针或者引用所指向的对象的实际派生类型。 RTTI的三个元素 dynamic_cast运算符 dynamic_cast概念: dynamic_cast运算符能够将基…...
![](https://img-blog.csdnimg.cn/31c6128b2f15480b9da46fa7e60bb3e2.png)
制作DBC文件
DBC文件是CAN通讯的密码本,Matlab的SimuLink中常用DBC作为CAN通讯的解析桥梁 制作DBC文件,内容是转速、位置&…...
![](https://img-blog.csdnimg.cn/f8174c4af80b4c5394c93421f7231a96.png)
【1.1】Java微服务:初识微服务
✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。 🍎个人主页:Meteors.的博客 💞当前专栏: 微服务 ✨特色专栏: 知识分享 &#x…...
![](https://img-blog.csdnimg.cn/9c8cc90b0b904c108a74132ea2ffd216.png#pic_center)
数据结构--串、数组、广义表
这里写目录标题 串定义案例引用串的类型定义以及存储结构抽象类型定义存储结构(顺序表较为常用)顺序存储结构链式存储结构 串的模式匹配算法(查找主串中是否有某个字串)BF算法KMP算法设计思想对字串的回溯进行了优化代码对next【j】进行优化 数组类型一维…...
![](https://www.ngui.cc/images/no-images.jpg)
白银挑战——链表高频面试算法题
算法通关村第一关–链表白银挑战笔记 开始时间:2023年7月18日14:39:36 链表 Java中定义一个链表 class ListNode {public int val;public ListNode next;ListNode(int x) {val x;next null;}}1、四种方法解决两个链表第一个公共子节点 解释一下什么是公共节点 如…...
![](https://www.ngui.cc/images/no-images.jpg)
海外腾讯云账号:腾讯云高性能计算平台 THPC
高性能计算平台(TencentCloud High Performance Computing,THPC)是一款腾讯云自研的高性能计算资源管理服务,集成腾讯云上的计算、存储、网络等产品资源,并整合 HPC 专用作业管理调度、集群管理等软件,向用…...
![](https://img-blog.csdnimg.cn/983b84c0c5964ef89395ac81bc5743de.png)
eclipse 最新版没有navigator视图如何解决
使用project exploere视图可以显示类似navigator视图 1.显示project exploere视图 window---->show view --->project exploere 2.project exploere视图转换为类似navigator视图 第一步:点击视图右上角三个点或者倒三角,点击fiters and custom…...
![](https://img-blog.csdnimg.cn/2dc2bac6353041e480fc0f1266a85df2.jpeg)
Zynq-Linux移植学习笔记之62- PL挂载复旦微flash
1、背景介绍 现在为了全国产化需要,之前所有的进口flash全部要换成国产flash 2、复旦微flash型号 其中EFM25QU256和EFM25QL256对标winbond的w25q256 nor flash 3、FPGA设置 复旦微flash只支持单线模式,当使用PL侧的IP核访问时,需要设置模式…...
![](https://img-blog.csdnimg.cn/b843ae0ba80d475caabba5ff730e7450.png)
SpringBoot复习:(2)Tomcat容器是怎么启动的?
SpringApplication的run方法包含如下代码: 其中调用的refreshContext代码如下: 其中调用的refresh方法片段如下: 其中调用的refresh方法代码如下: 其中调用的super.refresh方法代码如下: public void refresh() th…...
![](https://www.ngui.cc/images/no-images.jpg)
1 MobileHomeTopicApplication
目录 1 OrderApplication 1.1 引用文件 1.2 #region 字段 1.3 #region 属性 OrderApplication 引用文件using System; using...
![](https://img-blog.csdnimg.cn/43769b297ab44b57af96afeb7d5b2ce8.png)
mpi4py包安装报错
报错情况 #include <mpi.h>^~~~~~~compilation terminated.failure.removing: _configtest.c _configtest.oerror: Cannot compile MPI programs. Check your configuration!!![end of output]note: This error originates from a subprocess, and is likely not a probl…...
![](https://img-blog.csdnimg.cn/20190430103809698.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xsaGY2ODg=,size_16,color_FFFFFF,t_70)
100M家用宽带可做网站服务器吗/seo详细教程
批量更改数据的方法有很多,今天为您介绍的是使用Renamer这款专门为批量重命名文件而设计的一款工具,使用Renamer可以批量重命名文件,还可以批量更改文件的数据,操作简单,可快速地同时更改多个文件名称,支持…...
![](/images/no-images.jpg)
360网站备案查询/广州seo托管
5月8日消息,据《财富》网站报道,研究人员认为,一些流行的智能手机可能会过于紧密地监听用户的活动。 来自德国布伦瑞克工业大学(TUBS)的一个研究团队发现,有234款Android应用包含了被称为SilverPush的代码,用于监听嵌入…...
![](/images/no-images.jpg)
网站开发工具 晴天娃娃/网站建设开发
本文实例讲述了php实现基于pdo的事务处理方法。分享给大家供大家参考,具体如下:实例1:try {} catch () {} 形式$dsn mysql:dbnamecheyun_cms;host127.0.0.1;$user root;$password 111111;//采用预处理事务处理执行SQL操作//1.连接数据库tr…...
![](/images/no-images.jpg)
网络网站制作/常宁seo外包
什么是SourceAFIS?SourceAFIS是一种指纹识别引擎,可以获取一对人类的指纹图像并返回其相似性分数。 它可以进行1:1的比较以及高效的1:N搜索。 这是SourceAFIS算法的Java实现1.maven环境依赖引入com.machinezoo.sourceafissourceaf…...
![](https://img2018.cnblogs.com/blog/1517179/201901/1517179-20190115185543811-2079912430.png)
做外包的网站/爱站网排名
机器学习100天-day4,5,6,8逻辑回归 一,数据导入 import pandas as pd import numpy as np import matplotlib.pyplot as pltdataset pd.read_csv(D:\\100Days\datasets\Social_Network_Ads.csv) #print(dataset.head(5)) User ID Gender Age EstimatedSalary P…...
![](/images/no-images.jpg)
已注册域名怎么做网站呢/图片外链在线生成
用VC6.0的Sockets API实现一个聊天室程序1.VC网络编程及Windows Sockets API简介 VC对网络编程的支持有socket支持,WinInet支持,MAPI和ISAPI支持等。其中,Windows Sockets API是TCP/IP网络环境里,也是Internet上进行开发最为通用…...