Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >优化gin表单的错误提示信息

优化gin表单的错误提示信息

作者头像
编程黑洞
发布于 2023-03-06 11:11:25
发布于 2023-03-06 11:11:25
1.1K00
代码可运行
举报
文章被收录于专栏:编程黑洞编程黑洞
运行总次数:0
代码可运行

# 相关链接

gin官方例子 (opens new window)

文章的代码 (opens new window)

# 简单使用表单检验请求参数

创建一个简单的登录例子,我们对username和password绑定了required标签,代表着请求login接口的参数中必须包含这两个字段。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type User struct {
	UserName string `json:"username" binding:"required"`
	Password string `json:"password" binding:"required"`
}

func login(c *gin.Context) {

	var user User
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusOK, gin.H{"msg": err.Error()})
		return
	}

	if user.UserName != "admin" || user.Password != "123456" {
		c.JSON(http.StatusUnauthorized, gin.H{"msg": "unauthorized"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"msg": "you are logged in"})
}

func main() {
	r := gin.Default()
	r.POST("/login", login)
	r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

我们使用仅带有username去请求login接口,会输出如下,提示我们Password校验失败了,因为required的标签导致的。但是这个提示并不友好,我们需要进行优化展示。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{'msg': "Key: 'User.Password' Error:Field validation for 'Password' failed on the 'required' tag"}

# 翻译

我们需要对上面的提示信息进行一个翻译,并且可以支持各种语言的友好性提示。

我们在global/global.go文件中创建一个全局变量,该全局变量在后面的表单翻译中需要使用到

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import ut "github.com/go-playground/universal-translator"

var (
	Trans ut.Translator
)

initialize/validator.go文件中编写内容如下,获取gin中的validate对象,然后给该对象绑定中文和英文的友好提示信息,我们可以通过locale来设置我们需要使用中文还是英文的信息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func InitTrans(locale string) (err error) {

	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {

		// 翻译
		zhT := zh.New()
		enT := en.New()
		uni := ut.New(enT, zhT, enT)

		global.Trans, ok = uni.GetTranslator(locale)
		if !ok {
			return fmt.Errorf("uni.GetTranslator(%s) error", locale)
		}

		switch locale {
		case "zh":
			zh_translations.RegisterDefaultTranslations(v, global.Trans)
		case "en":
			en_translations.RegisterDefaultTranslations(v, global.Trans)
		default:
			en_translations.RegisterDefaultTranslations(v, global.Trans)
		}

		return
	}
	return
}

最后在main.go中的main方法下调用上面的InitTrans方法来初始化翻译内容。

再将login方法中ShouldBindJSON返回的error转成validator.ValidationErrors类型,该类型包含一个Translate方法,调用该方法,再将之前的全局变量Trans传入。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func login(c *gin.Context) {

	var user User
	if err := c.ShouldBindJSON(&user); err != nil {

		errs, ok := err.(validator.ValidationErrors)
		if !ok {
			// 非校验错误,其他错误直接返回
			c.JSON(http.StatusOK, gin.H{"msg": err.Error()})
			return
		}

		c.JSON(http.StatusOK, gin.H{"msg": errs.Translate(global.Trans)})
		return
	}

	if user.UserName != "admin" || user.Password != "123456" {
		c.JSON(http.StatusUnauthorized, gin.H{"msg": "unauthorized"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"msg": "you are logged in"})
}

func main() {
	err := initialize.InitTrans("zh")
	if err != nil {
		fmt.Printf("初始化翻译器错误, err = %s", err.Error())
		return
	}

	r := gin.Default()
	r.POST("/login", login)
	r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

我们再使用仅带有username字段去请求login接口,输出内容如下。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{'msg': {'User.Password': 'Password为必填字段'}}

但是,发现提示信息的key是User.Password,是表单对象和其字段名称,我们应该想要的是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{'msg': {'password': 'Password为必填字段'}}

# 优化返回字段的key

我们修改InitTrans方法,通过go-playground提供的方法RegisterTagNameFunc来将我们自定义的方法注册进去,该自定义方法的目的是修改上面的Password改为json中的password,可以改成json标签中的值作为返回。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func InitTrans(locale string) (err error) {

	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {

		//修改返回字段key的格式
		v.RegisterTagNameFunc(func(fld reflect.StructField) string {
			name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
			if name == "-" {
				return ""
			}
			return name
		})

		// 翻译
		zhT := zh.New()
		enT := en.New()
		uni := ut.New(enT, zhT, enT)

		global.Trans, ok = uni.GetTranslator(locale)
		if !ok {
			return fmt.Errorf("uni.GetTranslator(%s) error", locale)
		}

		switch locale {
		case "zh":
			zh_translations.RegisterDefaultTranslations(v, global.Trans)
		case "en":
			en_translations.RegisterDefaultTranslations(v, global.Trans)
		default:
			en_translations.RegisterDefaultTranslations(v, global.Trans)
		}

		return
	}
	return
}

再请求,响应如下,发现password已经改好了,但是User也想删除。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{'msg': {'User.password': 'password为必填字段'}}

我们在utils/validator.go文件中编写代码如下,该方法是用来删除User的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func RemoveTopStruct(fields map[string]string) map[string]string {
	res := map[string]string{}
	for field, err := range fields {
		res[field[strings.Index(field, ".")+1:]] = err
	}
	return res
}

再在翻译返回的错误信息包上该方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func login(c *gin.Context) {

	var user User
	if err := c.ShouldBindJSON(&user); err != nil {

		errs, ok := err.(validator.ValidationErrors)
		if !ok {
			// 非校验错误,其他错误直接返回
			c.JSON(http.StatusOK, gin.H{"msg": err.Error()})
			return
		}

		c.JSON(http.StatusOK, gin.H{"msg": utils.RemoveTopStruct(errs.Translate(global.Trans))})
		return
	}

	if user.UserName != "admin" || user.Password != "123456" {
		c.JSON(http.StatusUnauthorized, gin.H{"msg": "unauthorized"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"msg": "you are logged in"})
}

再执行,相应结果如下,这个就是我们想要的信息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{'msg': {'password': 'password为必填字段'}}

# 总结

个人觉的虽然gin灵活小巧,但是功能真的很不完善。每次一次输出友好信息,我们都要手动调用Translate来翻译,并且还需要通过RemoveTopStruct方法来修改返回的信息,按简单的来说,应该由框架来做,我们只需要通过配置,就能自动输出我们想要的友好提示信息才对。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
手把手,带你从零封装Gin框架(六):初始化 Validator & 封装 Response & 实现第一个接口
Gin 自带验证器返回的错误信息格式不太友好,本篇将进行调整,实现自定义错误信息,并规范接口返回的数据格式,分别为每种类型的错误定义错误码,前端可以根据对应的错误码实现后续不同的逻辑操作,篇末会使用自定义的 Validator 和 Response 实现第一个接口
用户10002156
2024/01/17
1.5K0
手把手,带你从零封装Gin框架(六):初始化 Validator & 封装 Response & 实现第一个接口
boss: 这小子还不会使用validator库进行数据校验,开了~~~
哈喽,大家好,我是asong。这是我的第十篇原创文章。这周在公司做项目,在做API部分开发时,需要对请求参数的校验,防止用户的恶意请求。例如日期格式,用户年龄,性别等必须是正常的值,不能随意设置。最开始在做这一部分的时候,我采用老方法,自己编写参数检验方法,统一进行参数验证。后来在同事CR的时候,说GIN有更好的参数检验方法,gin框架使用github.com/go-playground/validator进行参数校验,我们只需要在定义结构体时使用binding或validatetag标识相关校验规则,就可以进行参数校验了,很方便。相信也有很多小伙伴不知道这个功能,今天就来介绍一下这部分。
Golang梦工厂
2022/07/07
7810
如何在Go语言中实现表单验证?整一个validator吧!
文章链接:https://cloud.tencent.com/developer/article/2467471
南山竹
2024/11/20
1720
如何在Go语言中实现表单验证?整一个validator吧!
golang之数据验证validator
在web应用中经常会遇到数据验证问题,普通的验证方法比较繁琐,这里介绍一个使用比较多的包validator。
孤烟
2020/09/27
1.7K0
gin博客项目复盘--03错误处理、数据验证
错误处理 错误码标准化,接口返回错误代码,以供前端使用查看。 创建 /utils/errmsg/errmsg.go package errmsg const ( SUCCSE = 200 ERROR = 500 // code= 1000... 用户模块的错误 ERROR_USERNAME_USED = 1001 ERROR_PASSWORD_WRONG = 1002 //... ) var codemsg = map[int]string{ SUCCSE: "ok",
微客鸟窝
2022/11/07
4040
gin博客项目复盘--03错误处理、数据验证
Gin 11
使用 model binding 来将请求中的数据绑定到一个 model 中,形成一个结构体,Gin 目前支持绑定 JSON XML 和标准的表单数据 (foo=bar&boo=baz)
franket
2021/08/10
4830
Gin-Web-Framework官方指南中文(下篇)
ShouldBind,ShouldBindJSON,ShouldBindXML,ShouldBindQuery,ShouldBindYAML
小诚信驿站
2019/10/31
2.4K0
Gin-Web-Framework官方指南中文(下篇)
gin中validator模块的源码分析
众所周知,在api层需要使用gin.Context中的ShouldBindJSON方法来对request中的json字段进行校验,例子如下:
编程黑洞
2023/03/06
4360
Go: Gin框架中的binding验证器使用指南
在Gin框架中,数据绑定和验证是开发API时不可或缺的部分。Gin提供了强大的binding功能,允许我们将请求的数据绑定到结构体,并通过标签进行数据验证。本文将详细讲解如何在Gin中使用binding验证器进行数据验证,并提供代码示例帮助理解。
运维开发王义杰
2024/05/31
1.5K0
Go: Gin框架中的binding验证器使用指南
Go语言WEB框架之Gin
文档:https://gin-gonic.com/zh-cn/docs/quickstart/
码客说
2022/10/05
1.3K0
gin框架之表单验证
实践经验告诉我们,前端提交过来的一切数据都可以信任,都必须做校验。所以我们必须要进行数据校验!那么在gin框架中怎么做校验的呢!gin默认使用的是validator库,有兴趣的小伙伴可以去自己看一下文档,github地址是: https://github.com/go-playground/validator gin框架为我们整合和一些基础的模型绑定和数据校验,比如: ShouldBind ShouldBindQuery ShouldBindUri ShouldBindJSON ShouldBindHe
大话swift
2020/03/27
2.2K0
你会高效写http服务器吗?Gin实战演练
胖sir开始捣鼓http服务器,在寻求一种高效的解决方式且高性能的解决方式...
阿兵云原生
2023/02/16
2.2K0
初学gin
已经放弃goframe框架,对待新手不是很友好,社区圈子也很小。因为我自身的话是没有go语言的编程基础的,所以导致了我看不太懂那个框架,不过看很多人都说goframe封装的很好,有人吐槽有人夸,开源的框架嘛,这些都是在所难免的。
是小张啊喂
2021/08/09
7930
Go 小清单
这个项目超级简单,前端代码是已经做好的,直接去大佬仓库clone就行,只不过教程比较久远了,所以代码需要一些调整。
f1sh
2024/07/30
1450
在gin框架中使用JWT
JWT全称JSON Web Token是一种跨域认证解决方案,属于一个开放的标准,它规定了一种Token实现方式,目前多用于前后端分离项目和OAuth2.0业务场景下。
luckpunk
2023/09/10
5710
02 . Go框架之Gin框架从入门到熟悉(数据解析和绑定,渲染,重定向,同步异步,中间件)
json,结构体,xml, yaml类似于java的properties,protobuf
iginkgo18
2020/11/04
1.6K0
02 . Go框架之Gin框架从入门到熟悉(数据解析和绑定,渲染,重定向,同步异步,中间件)
Go语言(十三)Gin Web框架
Gin Web框架 简介 基于httprouter开发的web框架:https://github.com/gin-gonic/gin 提供Martini风格的API,但比Martini要快40倍 非常轻量级,使用简洁 Gin框架的安装与使用 安装: go get -u github.com/gin-gonic/gin 基本使用 import "github.com/gin-gonic/gin" func main() { r := gin.Default() r.GET("/ping", fu
alexhuiwang
2020/09/24
9170
Go语言(十三)Gin Web框架
gin博客项目复盘--05 JWT全面解读、详细使用步骤
JWT由3部分组成:标头(Header)、有效载荷(Payload)和签名(Signature)。在传输的时候,会将JWT的3部分分别进行Base64编码后用.进行连接形成最终传输的字符串。
微客鸟窝
2022/11/07
5570
gin博客项目复盘--05 JWT全面解读、详细使用步骤
Gin 框架怎么使用自定义验证器?
阅读上面这段代码,我们定义一个 validator.Func 类型的函数变量,参数入参的类型是 validator.FieldLevel,返回结果是一个 bool 类型的变量。
frank.
2024/11/19
2040
Gin 框架怎么使用自定义验证器?
Go 和 Gin 打造一个带图库功能的随机图片 API?让我们一起走进 Go Web 开发的奇妙世界!
今日推荐:Spring AI再更新:如何借助全局参数实现智能数据库操作与个性化待办管理
繁依Fanyi
2024/11/15
1500
推荐阅读
相关推荐
手把手,带你从零封装Gin框架(六):初始化 Validator & 封装 Response & 实现第一个接口
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验