Golang中如何在自定义验证器内从gin.Context获取URL
Golang中如何在自定义验证器内从gin.Context获取URL 大家好,我正在尝试在自定义验证器中使用 gin.Context 引用来获取 Gin 请求的 URL 路径,但是当我调用 /test2 这个 URL 时,我无法在验证器中获取到 /test1 这个 URL,上下文始终给我的是 /test2 这个 URL,如下图所示;
package main
import (
"context"
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
// Macro ...
type Macro struct {
IDMacro int `db:"idMacro" form:"idMacro" binding:"required_route_oneof=GET;/test1"`
IDCentral int `db:"idCentral" form:"idCentral" binding:"required_route_oneof=GET;/test1 GET;/test2"`
}
type Validator struct {
C *gin.Context
}
func (cv *Validator) RequiredRouteOneOf(ctx context.Context, fl validator.FieldLevel) bool {
fmt.Printf("%s %s\r\n", cv.C.Request.Method, cv.C.Request.URL.Path)
return true
}
func test1(c *gin.Context) {
inputData := Macro{}
if err := c.ShouldBindQuery(&inputData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
}
func test2(c *gin.Context) {
inputData := Macro{}
if err := c.ShouldBindQuery(&inputData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
}
func main() {
r := gin.Default()
// Use the custom validator middleware
r.Use(func(c *gin.Context) {
context := &Validator{c}
_ = binding.Validator.Engine().(*validator.Validate).RegisterValidationCtx("required_route_oneof", context.RequiredRouteOneOf)
c.Next()
})
r.GET("/test1", test1)
r.GET("/test2", test2)
r.Run(":3752")
}

有人知道为什么会发生这种情况吗?
更多关于Golang中如何在自定义验证器内从gin.Context获取URL的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang中如何在自定义验证器内从gin.Context获取URL的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在自定义验证器中获取正确的URL路径,需要将验证器注册移到中间件外部,并使用gin.Context的副本。问题在于每次请求都会重新注册验证器,导致上下文被覆盖。以下是修正后的代码:
package main
import (
"context"
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
// Macro ...
type Macro struct {
IDMacro int `db:"idMacro" form:"idMacro" binding:"required_route_oneof=GET;/test1"`
IDCentral int `db:"idCentral" form:"idCentral" binding:"required_route_oneof=GET;/test1 GET;/test2"`
}
type contextGetter func() *gin.Context
var getContext contextGetter
func RequiredRouteOneOf(ctx context.Context, fl validator.FieldLevel) bool {
if getContext != nil {
c := getContext()
fmt.Printf("%s %s\r\n", c.Request.Method, c.Request.URL.Path)
}
return true
}
func test1(c *gin.Context) {
inputData := Macro{}
if err := c.ShouldBindQuery(&inputData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
}
func test2(c *gin.Context) {
inputData := Macro{}
if err := c.ShouldBindQuery(&inputData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
}
func main() {
r := gin.Default()
// 注册验证器(只注册一次)
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
_ = v.RegisterValidationCtx("required_route_oneof", RequiredRouteOneOf)
}
// 中间件设置当前上下文
r.Use(func(c *gin.Context) {
getContext = func() *gin.Context {
return c
}
c.Next()
// 清理上下文引用
getContext = nil
})
r.GET("/test1", test1)
r.GET("/test2", test2)
r.Run(":3752")
}
关键修改:
- 将验证器注册移到中间件外部,确保只注册一次
- 使用闭包函数
getContext动态获取当前请求的上下文 - 在中间件中设置和清理上下文引用
这样当访问/test1时,验证器会正确输出GET /test1;访问/test2时输出GET /test2。

