概述
ginvalidator 是一组 Gin 中间件,它包装了我的另一个开源包 validatorgo 提供的广泛的验证器和消毒器集合。它还使用流行的开源包 gjson 进行 JSON 字段语法,提供从 JSON 对象中高效查询和提取数据的功能。
它允许您以多种方式组合它们,以便您可以验证和清理您的 Gin 请求,并提供工具来确定请求是否有效,以及根据您的验证器匹配哪些数据。
它基于流行的js/express库express-validator
支持
此版本的 ginvalidator 要求您的应用程序在 Go 1.16 上运行。
它还经验证可与 Gin 1.x.x.
基本原理
为什么不使用?
- 手写验证器: 您可以手动编写自己的验证逻辑,但这很快就会变得重复且混乱。每次需要新的验证时,您都在一遍又一遍地编写相同类型的代码。很容易出错,而且维护起来很痛苦。
- Gin 内置的模型绑定和验证: Gin 内置了验证,但它并不适合所有人。结构标签具有限制性,并使您的代码更难以阅读,尤其是当您需要复杂的规则时。另外,验证与模型联系得太紧密,这不利于灵活性。
- 其他库(如 Galidator): 还有其他库,但它们通常感觉对其所做的事情来说过于复杂。它们需要比您预期更多的设置和工作,特别是当您只想要一个简单、直接的验证解决方案时。
安装
确保您的计算机上安装了 Go。
第 1 步:创建一个新的 Go 模块
- 使用您选择的名称创建一个空文件夹。
- 打开终端,导航 (cd) 到该文件夹,并初始化一个新的 Go 模块:
go mod init example.com/learning
第2步:安装所需的软件包
使用 go get 安装必要的软件包。
- 安装杜松子酒:
go get -u github.com/gin-gonic/gin
- 安装ginvalidator:
go get -u github.com/bube054/ginvalidator
入门
学习东西的最好方法之一就是通过实例!因此,让我们卷起袖子,开始编写代码吧。
设置
首先需要的是运行一个 Gin 服务器。让我们实现一个向某人打招呼的功能;为此,创建一个 main.go 然后添加以下代码:
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/hello", func(ctx *gin.Context) { person := ctx.Query("person") ctx.String(http.StatusOK, "Hello, %s!", person) }) r.Run() // listen and serve on 0.0.0.0:8080 }
现在通过在终端上执行 go run main.go 来运行此文件。
go mod init example.com/learning
HTTP 服务器应该正在运行,您可以打开 http://localhost:8080/hello?person=John 向 John 致敬!
? 提示:
您可以将 Air 与 Go 和 Gin 结合使用来实现实时重新加载。每当文件更改时,这些都会自动重新启动服务器,因此您不必自己执行此操作!
添加验证器
所以服务器正在工作,但存在问题。最值得注意的是,当某人的名字未设置时,您不想向某人打招呼。
例如,访问 http://localhost:8080/hello 将打印“Hello,”。
这就是 ginvalidator 派上用场的地方。它提供了用于验证您的请求的验证器、消毒器和修饰符。
让我们添加一个验证器和一个修饰符来检查人员查询字符串不能为空,验证器名为 Empty ,修饰符名为 Not:
go get -u github.com/gin-gonic/gin
? 注意:
为简洁起见,代码示例中使用 gv 作为 ginvalidator 的别名。
现在,重新启动服务器,然后再次访问 http://localhost:8080/hello。嗯,它仍然打印“Hello,!”...为什么?
处理验证错误
ginvalidator验证链不会自动向用户报告验证错误。
原因很简单:当您添加更多验证器或更多字段时,您希望如何收集错误?您想要一份所有错误的列表,每个字段只有一个,整体只有一个......?
所以下一个明显的步骤是再次更改上面的代码,这次使用 ValidationResult 函数验证验证结果:
go get -u github.com/bube054/ginvalidator
现在,如果您再次访问 http://localhost:8080/hello,您将看到以下 JSON 内容,为了清晰起见,我们进行了格式化:
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/hello", func(ctx *gin.Context) { person := ctx.Query("person") ctx.String(http.StatusOK, "Hello, %s!", person) }) r.Run() // listen and serve on 0.0.0.0:8080 }
现在,这告诉我们的是
- 此请求中只有一个错误;
- 这个字段称为 person;
- 它位于查询字符串中(位置:“queries”);
- 给出的错误消息是“无效值”。
这是一个更好的场景,但仍然可以改进。我们继续吧。
创建更好的错误消息
所有请求位置验证器都接受可选的第二个参数,它是用于格式化错误消息的函数。如果提供 nil,将使用默认的通用错误消息,如上面的示例所示。
go run main.go
现在,如果您再次访问 http://localhost:8080/hello,您将看到以下 JSON 内容,并带有新的错误消息:
package main import ( "net/http" gv "github.com/bube054/ginvalidator" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/hello", gv.NewQuery("person", nil). Chain(). Not(). Empty(nil). Validate(), func(ctx *gin.Context) { person := ctx.Query("person") ctx.String(http.StatusOK, "Hello, %s!", person) }) r.Run() }
访问经过验证/清理的数据
您可以使用 GetMatchedData,它会自动收集 ginvalidator 已验证和/或清理的所有数据。然后可以使用 MatchedData 的 Get 方法访问此数据:
go mod init example.com/learning
打开 http://localhost:8080/hello?person=John 向 John 致敬!
可用位置有 BodyLocation、CookieLocation、QueryLocation、ParamLocation 和 HeaderLocation。
每个位置都包含一个 String 方法,该方法返回存储经过验证/清理的数据的位置。
净化输入
虽然用户不能再发送空人名,但它仍然可以将 HTML 注入您的页面!这称为跨站脚本漏洞 (XSS)。
让我们看看它是如何工作的。转到 http://localhost:8080/hello?person=John,您应该看到“Hello, John!”。
虽然此示例很好,但攻击者可以将人员查询字符串更改为 <script> 。加载自己的 JavaScript 的标签可能有害。<br>
在这种情况下,缓解 ginvalidator 问题的一种方法是使用消毒剂,特别是 Escape,它将特殊的 HTML 字符与其他可以表示为文本的字符进行转换。<br>
</script>
go get -u github.com/gin-gonic/gin
现在,如果您重新启动服务器并刷新页面,您将看到“Hello, John!”。我们的示例页面不再容易受到 XSS 攻击!
⚠️ 注意:
ginvalidator 在清理期间不会修改 http.Request 值。要访问清理后的数据,请始终使用 GetMatchedData 函数。
验证链
验证链是 ginvalidator 中的主要概念之一,因此了解它很有用,以便您可以有效地使用它。
但是不用担心:如果您已经阅读了入门指南,那么您已经在不知不觉中使用了验证链!
什么是验证链?
验证链是使用以下函数创建的,每个函数都针对 HTTP 请求中的特定位置:
- NewBody:验证来自 http.Request 正文的数据。它的位置是 BodyLocation。
- NewCookie:验证来自 http.Request cookie 的数据。它的位置是 CookieLocation。
- NewHeader:验证来自 http.Request 标头的数据。它的位置是 HeaderLocation。
- NewParam:验证 Gin 路由参数中的数据。它的位置是 ParamLocation。
- NewQuery:验证来自 http.Request 查询参数的数据。它的位置是 QueryLocation。
它们之所以有这个名字,是因为它们用验证(或清理)来包装字段的值,并且它的每个方法都返回自身。
这种模式通常称为方法链,因此称为验证链。
验证链不仅具有许多用于定义验证、清理和修改的有用方法,而且还具有返回 Gin 中间件处理函数的 Validate 方法。
这是验证链通常如何使用以及如何阅读的示例:
go mod init example.com/learning
特征
验证链具有三种方法:验证器、消毒器和修饰器。
验证器确定请求字段的值是否有效。这意味着检查该字段是否采用您期望的格式。例如,如果您正在构建注册表单,您的要求可能是用户名必须是电子邮件地址,并且密码的长度必须至少为 8 个字符。
如果该值无效,则会使用一些错误消息记录该字段的错误。然后可以稍后在 Gin 路由处理程序中检索此验证错误并将其返回给用户。
他们是:
- 自定义验证器
- 包含
- 等于
- 阿坝路由
- 之后
- 阿尔法
- 字母数字
- ASCII
- Base32
- Base58
- Base64
- 之前
- 比克
- 布尔值
- BTC地址
- 字节长度
- 信用卡
- 货币
- DataURI
- 日期
- 十进制
- 可整除
- EAN
- 电子邮件
- 空
- 以太坊地址
- 漂浮
- FQDN
- 货运集装箱ID
- 全宽
- 半宽
- 哈希
- 十六进制
- 十六进制颜色
- HSL
- 国际银行账号
- 身份证
- IMEI
- 在
- 国际
- IP
- IP范围
- ISIN
- ISO4217
- ISO6346
- ISO6391
- ISO8601
- ISO31661Alpha2
- ISO31661Alpha3
- ISO31661 数字
- ISRC
- ISSN
- JSON
- 拉长
- 车牌
- 语言环境
- 小写
- LuhnNumber
- Mac地址
- MagnetURI
- MailtoURI
- MD5
- 哑剧类型
- 手机
- MongoID
- 多字节
- 数字
- 八进制
- 护照号码
- 港口
- 邮政编码
- RFC3339
- RGB颜色
- SemVer
- 蛞蝓
- 强密码
- 税号
- 代理对
- 时间
- ULID
- 大写
- 网址
- UUID
- 可变宽度
- 增值税
- 已列入白名单
- 比赛
消毒剂会改变字段值。它们对于消除值中的噪音很有用,甚至可能提供一些针对威胁的基本防线。
Sanitizers 将更新后的字段值保留回 Gin 上下文中,以便其他 ginvalidator 函数、您自己的路由处理程序代码,甚至其他中间件都可以使用它。
他们是:
- 定制消毒剂
- 黑名单
- 逃脱
- LTrim
- 标准化电子邮件
- RTrim
- 脱衣低
- 转布尔值
- 迄今为止
- 漂浮
- ToInt
- 修剪
- 逃亡
- 白名单
修饰符定义验证链运行时的行为方式。
他们是:
- 保释
- 如果
- 不是
- 跳过
- 可选
? 注意:
这些方法在 pkg.go.dev ginvalidator 文档中使用 GoDoc 进行了完整记录。如果有任何细节不清楚,您可能还需要参考 validatorgo 包中的相关函数以获取更多上下文,我将在下面进行解释。
标准验证器/消毒器
验证链公开的所有功能实际上都来自 validatorgo,这是我的其他开源 go 包之一,专门从事字符串验证/清理。请检查一下,加星标并分享???,谢谢。
这包括所有 validatorgo 验证器和清理程序,从常用的 IsEmail、IsLength 和 Trim 到更小众的 IsISBN、IsMultibyte 和 StripLow!
这些在 ginvalidator 中被称为标准验证器和标准消毒器。但没有来自 validatorgo 的 Is 前缀。
链接顺序
在验证链上调用方法的顺序通常很重要。
它们几乎总是按照指定的顺序运行,因此您只需阅读验证链的定义(从第一个链接方法到最后一个方法)就可以知道验证链将做什么。
以下面的代码片段为例:
go mod init example.com/learning
在这种情况下,如果用户传递一个仅由空格组成的“search_query”值,它不会为空,因此验证通过。但由于 .Trim() 消毒剂存在,空格将被删除,并且该字段将变为空,因此您实际上最终会得到误报。
现在,将其与以下代码片段进行比较:
go get -u github.com/gin-gonic/gin
这条链将更明智地删除空格,然后验证值是否不为空。
此规则的一个例外是 .Optional():它可以放置在链中的任何一点,并将该链标记为可选。
重用验证链
如果您希望重用同一个链,最好从函数中返回它们:
go get -u github.com/bube054/ginvalidator
领域选择
在 ginvalidator 中,字段是任何经过验证或清理的值,并且它是字符串。
几乎每个函数或值都以某种方式由 ginvalidator 引用字段返回。因此,了解字段路径语法对于选择验证字段以及访问验证错误或验证数据时非常重要。
句法
-
正文字段仅对以下内容类型有效:
- application/json:这使用 GJSON 路径语法来提取值。详细信息请参阅链接文档。
- 示例:
go mod init example.com/learning
使用路径 user.name,提取的值为“John”。
- application/x-www-form-urlencoded:通常用于 HTML 表单提交。字段在正文中作为键值对提交。
- 示例:
go get -u github.com/gin-gonic/gin
身体:
go get -u github.com/bube054/ginvalidator
字段“name”的值为“John”,“email”的值为“john.doe@example.com”。
- multipart/form-data:常用于文件上传或随文件提交表单数据时。
- 示例:
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/hello", func(ctx *gin.Context) { person := ctx.Query("person") ctx.String(http.StatusOK, "Hello, %s!", person) }) r.Run() // listen and serve on 0.0.0.0:8080 }
身体:
go run main.go
字段“name”的值为“John”,“file”为上传的文件。
-
查询字段对应URL搜索参数,其值自动为Gin未转义的url。
示例:- 字段:“姓名”,值:“约翰”
package main import ( "net/http" gv "github.com/bube054/ginvalidator" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/hello", gv.NewQuery("person", nil). Chain(). Not(). Empty(nil). Validate(), func(ctx *gin.Context) { person := ctx.Query("person") ctx.String(http.StatusOK, "Hello, %s!", person) }) r.Run() }
- 字段:“full_name”,值:“John Doe”
package main import ( "net/http" gv "github.com/bube054/ginvalidator" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/hello", gv.NewQuery("person", nil). Chain(). Not(). Empty(nil). Validate(), func(ctx *gin.Context) { result, err := gv.ValidationResult(ctx) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ "message": "The server encountered an unexpected error.", }) return } if len(result) != 0 { ctx.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{ "errors": result, }) return } person := ctx.Query("person") ctx.String(http.StatusOK, "Hello, %s!", person) }) r.Run() }
-
Param 字段 表示 URL 路径参数,其值会被 ginvalidator 自动转义。
示例:- 字段:“id”,值:“123”
{ "errors": [ { "location": "queries", "message": "Invalid value", "field": "person", "value": "" } ] }
-
标头字段是HTTP请求标头,它们的值不是未转义的。如果您提供非规范标头密钥,将会出现日志警告。
示例:- 字段:“用户代理”,值:“Mozilla/5.0”
package main import ( "net/http" gv "github.com/bube054/ginvalidator" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/hello", gv.NewQuery("person", func(initialValue, sanitizedValue, validatorName string) string { return "Please enter your name." }, ).Chain(). Not(). Empty(nil). Validate(), func(ctx *gin.Context) { result, err := gv.ValidationResult(ctx) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ "message": "The server encountered an unexpected error.", }) return } if len(result) != 0 { ctx.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{ "errors": result, }) return } person := ctx.Query("person") ctx.String(http.StatusOK, "Hello, %s!", person) }) r.Run() }
-
Cookie 字段 是 HTTP cookie,其值自动为 Gin 未转义的 url。
示例:- 字段:“session_id”,值:“abc 123”
{ "errors": [ { "location": "queries", "message": "Please enter your name.", "field": "person", "value": "" } ] }
自定义快速验证器
如果您正在构建的服务器不是一个非常简单的服务器,那么迟早您将需要验证器、清理器和错误消息,而不仅仅是 ginvalidator 中内置的内容。
自定义验证器和消毒器
ginvalidator 无法满足您并且您可能会遇到的一个经典需求是在用户注册时验证电子邮件地址是否正在使用。
可以通过实现自定义验证器在 ginvalidator 中执行此操作。
CustomValidator 是验证链上可用的方法,它接收特殊函数 CustomValidatorFunc,并且必须返回一个布尔值来确定字段是否有效。
CustomSanitizer 也是验证链上可用的方法,它接收特殊函数 CustomSanitizerFunc,并且必须返回新的清理值。
实现自定义验证器
CustomValidator 可以通过使用 goroutine 和sync.WaitGroup 来异步处理并发操作。在验证器中,您可以为每个异步任务启动 goroutine,并将每个任务添加到 WaitGroup。所有任务完成后,验证器应返回一个布尔值。
例如,为了检查电子邮件是否未被使用:
go mod init example.com/learning
或者您也可以验证密码是否与重复匹配:
go get -u github.com/gin-gonic/gin
⚠️ 注意:
如果请求正文将被多次访问(无论是在同一验证链中、在同一请求上下文的另一个验证链中还是在后续处理程序中),请确保在每次读取后重置请求正文。如果不这样做,再次读取正文时可能会导致错误或数据丢失。
实施自定义消毒剂
CustomSanitizer 没有太多规则。无论它们返回什么值,都是该字段将获取的新值。
自定义清理程序还可以通过使用 goroutine 和sync.WaitGroup 来异步处理并发操作。
go get -u github.com/bube054/ginvalidator
错误信息
每当字段值无效时,都会为其记录一条错误消息。
默认错误消息是“无效值”,它根本无法描述错误的内容,因此您可能需要对其进行自定义。您可以通过
进行定制
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/hello", func(ctx *gin.Context) { person := ctx.Query("person") ctx.String(http.StatusOK, "Hello, %s!", person) }) r.Run() // listen and serve on 0.0.0.0:8080 }
- 初始值是从请求中提取的原始值(在任何清理之前)。
- sanitizedValue 是经过清理后的值(如果适用)。
- validatorName 是失败的验证器的名称,有助于识别未通过的验证规则。
有关验证器名称的完整列表,请参阅 ginvalidator 常量。
维护者
- bube054 - Attah Gbubemi David(作者)
以上是使用 ginvalidator 简化 Go 中的 Gin 输入验证的详细内容。更多信息请关注PHP中文网其他相关文章!

C 更适合需要直接控制硬件资源和高性能优化的场景,而Golang更适合需要快速开发和高并发处理的场景。1.C 的优势在于其接近硬件的特性和高度的优化能力,适合游戏开发等高性能需求。2.Golang的优势在于其简洁的语法和天然的并发支持,适合高并发服务开发。

Golang在实际应用中表现出色,以简洁、高效和并发性着称。 1)通过Goroutines和Channels实现并发编程,2)利用接口和多态编写灵活代码,3)使用net/http包简化网络编程,4)构建高效并发爬虫,5)通过工具和最佳实践进行调试和优化。

Go语言的核心特性包括垃圾回收、静态链接和并发支持。1.Go语言的并发模型通过goroutine和channel实现高效并发编程。2.接口和多态性通过实现接口方法,使得不同类型可以统一处理。3.基本用法展示了函数定义和调用的高效性。4.高级用法中,切片提供了动态调整大小的强大功能。5.常见错误如竞态条件可以通过gotest-race检测并解决。6.性能优化通过sync.Pool重用对象,减少垃圾回收压力。

Go语言在构建高效且可扩展的系统中表现出色,其优势包括:1.高性能:编译成机器码,运行速度快;2.并发编程:通过goroutines和channels简化多任务处理;3.简洁性:语法简洁,降低学习和维护成本;4.跨平台:支持跨平台编译,方便部署。

关于SQL查询结果排序的疑惑学习SQL的过程中,常常会遇到一些令人困惑的问题。最近,笔者在阅读《MICK-SQL基础�...

golang ...

Go语言中如何对比并处理三个结构体在Go语言编程中,有时需要对比两个结构体的差异,并将这些差异应用到第�...


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

Atom编辑器mac版下载
最流行的的开源编辑器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

Dreamweaver CS6
视觉化网页开发工具

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),