当前位置:网站首页>gin 参数验证
gin 参数验证
2022-07-29 06:20:00 【Mar丶流年】
前言
gin的参数验证是集成了 https://github.com/go-playground
参数验证
使用 gin.Context中ShouldBind(obj)方法
obj 通过tag设置验证规则
接收参数字段设置
//json:“json_name” 代表json格式收取json_name参数值到Name
//form:"form_name" 代表表单格式收取form_name参数值到Name
//xml:"xml_name" 代表xml格式收取xml_name参数到Name
type Register struct {
Name string `json:"json_name" form:"form_name" xml:"xml_name"`
}
参数条件限制
更多tag 请查看官方文档(https://pkg.go.dev/github.com/go-playground/validator/v10#hdr-Using_Validator_Tags)
//binding:后为条件限制
//required:必填
//min:最小长度
//max:最大长度
type Register struct {
Name string `json:"json_name" form:"form_name" xml:"xml_name" binding:"required,min=3,max=10"`
}
输出错误信息
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
type Register struct {
Name string `json:"json_name" form:"form_name" xml:"xml_name" binding:"required,min=3,max=10"`
}
func main() {
r := gin.Default()
r.POST("/register", func(c *gin.Context) {
r := &Register{
}
err := c.ShouldBind(r)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "ok",
})
})
r.Run(":8080")
}
验证信息中文处理
未进行中文处理的验证错误信息是这个样子的:Key: ‘Register.Name’ Error:Field validation for ‘Name’ failed on the ‘required’ tag
首先先注册翻译器,然后创建通用翻译器,从通用翻译器中获取指定的翻译器(封装过的),然后将其绑定到gin的验证器上。
验证器返回的错误转换成 go-playground 的 ValidationErrors类型,调用Translate 指定翻译器进行翻译
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
en_translation "github.com/go-playground/validator/v10/translations/en"
zh_translation "github.com/go-playground/validator/v10/translations/zh"
"net/http"
)
type Register struct {
Name string `json:"json_name" form:"form_name" xml:"xml_name" binding:"required,min=3,max=10"`
}
var trans ut.Translator
func initTranslator(language string) error {
//转换成go-playground的validator
validate, ok := binding.Validator.Engine().(*validator.Validate)
if ok {
//创建翻译器
zhT := zh.New()
enT := en.New()
//创建通用翻译器
//第一个参数是备用语言,后面的是应当支持的语言
uni := ut.New(enT, enT, zhT)
//从通过中获取指定语言翻译器
trans, ok = uni.GetTranslator(language)
if !ok {
return fmt.Errorf("not found translator %s", language)
}
//绑定到gin的验证器上,对binding的tag进行翻译
switch language {
case "zh":
err := zh_translation.RegisterDefaultTranslations(validate, trans)
if err != nil {
return err
}
default:
err := en_translation.RegisterDefaultTranslations(validate, trans)
if err != nil {
return err
}
}
}
return nil
}
func main() {
err := initTranslator("zh")
if err != nil {
panic(err)
}
r := gin.Default()
r.POST("/register", func(c *gin.Context) {
r := &Register{
}
err := c.ShouldBind(r)
if err != nil {
if errors, ok := err.(validator.ValidationErrors); ok {
//调用指定翻译器进行翻译
c.JSON(http.StatusBadRequest, gin.H{
"error": errors.Translate(trans),
})
} else {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
}
return
}
c.JSON(http.StatusOK, gin.H{
"message": "ok",
})
})
r.Run(":8080")
}
返回的错误格式处理
上面返回的错误格式是这个样子的
{
"error": {
"Register.Name": "Name为必填字段"
}
}
首先我通过JSON格式请求的,error中的key应该是json_name,value
应该是json_name为必填字段
理想型数据结构
{
"error": {
"json_name": "json_name为必填字段"
}
}
json_name 可以通过 RegisterTagNameFunc 设置返回字段json_name,但是就算设置json_name,但是key还是 Register.json_name。
解决方案:对错误结果进行处理,剔除 Register 部分
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
en_translation "github.com/go-playground/validator/v10/translations/en"
zh_translation "github.com/go-playground/validator/v10/translations/zh"
"net/http"
"reflect"
"strings"
)
type Register struct {
Name string `json:"json_name" form:"form_name" xml:"xml_name" binding:"required,min=3,max=10"`
}
var trans ut.Translator
func initTranslator(language string) error {
//转换成go-playground的validator
validate, ok := binding.Validator.Engine().(*validator.Validate)
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
// json:"json_name" form:"form_name" xml:"xml_name" binding:"required,min=3,max=10"
// 设置返回 json tag 中的内容 如:json_names
return field.Tag.Get("json")
})
if ok {
//创建翻译器
zhT := zh.New()
enT := en.New()
//创建通用翻译器
//第一个参数是备用语言,后面的是应当支持的语言
uni := ut.New(enT, enT, zhT)
//从通过中获取指定语言翻译器
trans, ok = uni.GetTranslator(language)
if !ok {
return fmt.Errorf("not found translator %s", language)
}
//对binding的tag进行翻译
switch language {
case "zh":
err := zh_translation.RegisterDefaultTranslations(validate, trans)
if err != nil {
return err
}
default:
err := en_translation.RegisterDefaultTranslations(validate, trans)
if err != nil {
return err
}
}
}
return nil
}
func remove(errors map[string]string) map[string]string {
result := map[string]string{
}
for key, value := range errors {
result[key[strings.Index(key, ".")+1:]] = value
}
return result
}
func main() {
err := initTranslator("zh")
if err != nil {
panic(err)
}
r := gin.Default()
r.POST("/register", func(c *gin.Context) {
r := &Register{
}
err := c.ShouldBind(r)
if err != nil {
if errors, ok := err.(validator.ValidationErrors); ok {
//调用指定翻译器进行翻译
c.JSON(http.StatusBadRequest, gin.H{
//调用自定义函数去除Register部分
"error": remove(errors.Translate(trans)),
})
} else {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
}
return
}
c.JSON(http.StatusOK, gin.H{
"message": "ok",
})
})
r.Run(":8080")
}
边栏推荐
- Invalid access control
- 太空射击第17课: Game Over (結束)
- Teacher wangshuyao wrote the notes of operations research course 00 in the front
- 【charles日常问题】开启charles,使用不了钉钉
- Teacher Wu Enda's machine learning course notes 02 univariate linear regression
- Leetcode-592: fraction addition and subtraction
- 记 - 踩坑-实时数仓开发 - doris/pg/flink
- Not so simple singleton mode
- 【解决方案】ERROR: lib/bridge_generated.dart:837:9: Error: The parameter ‘ptr‘ of the method ‘FlutterRustB
- Implementation of DDP cluster distributed training under pytoch multi GPU conditions (brief introduction - from scratch)
猜你喜欢
VMware16安装虚拟机遇到的问题
实战!聊聊如何解决MySQL深分页问题
数组的子集不能累加出的最小正数
vim文本编辑器的一些使用小技巧
猜数字//第一次使用生成随机数
Image noise and matrix inversion
Flink real-time warehouse DWD layer (transaction domain - additional purchase dimension degradation processing) template code
我的创业邻居们
Unity free element special effect recommendation
SSH免密登录-两台虚拟机建立免密通道 双向信任
随机推荐
Simulation volume leetcode [normal] 222. number of nodes of complete binary tree
Google fragmented notes JWT (Draft)
Pytorch多GPU条件下DDP集群分布训练实现(简述-从无到有)
Hj37 statistics of the total number of rabbits per month Fibonacci series
Ali gave several SQL messages and asked how many tree search operations need to be performed?
How to write controller layer code gracefully?
Difference between CNAME record and a record
模拟卷Leetcode【普通】081. 搜索旋转排序数组 II
Simulation volume leetcode [normal] 061. rotating linked list
Dbasql interview questions
Flink real time warehouse DWD layer (traffic domain) template code
[CF1054H] Epic Convolution——数论,卷积,任意模数NTT
Can MySQL export tables regularly?
Analog volume leetcode [normal] 093. Restore IP address
Unity探索地块通路设计分析 & 流程+代码具体实现
Overview of database system
外包干了3年,跳槽后转自动化测试工资是原来的2倍,秘诀原来是......
Teacher wangshuyao's notes on operations research 05 linear programming and simplex method (concept, modeling, standard type)
约瑟夫环问题
【Redis】Redis开发规范与注意事项