在中间件中绑定查询
Bind Query inside middleware
我正在尝试编写一个“Binder”中间件,它将使用带有 gin 的结构类型验证任何请求查询 bindings/validators
例如,假设我有一个名为 /api/subject
的端点组,它要求查询字符串具有主题代码和一个 ID,将使用以下结构(称为 entity.Subject
):
type Subject struct {
Code string `binding:"required,alphanum"`
ID string `binding:"required,alphanum,len=4"`
}
这只是一个示例,但我希望能够将任何结构类型传递给此中间件,因为我希望在未来的处理程序上访问查询数据而不必担心查询验证。
所以我尝试了这样的事情:
func Binder(t reflect.Type) gin.HandlerFunc {
return func(c *gin.Context) {
obj := reflect.New(t).Elem().Interface()
if err := c.BindQuery(&obj); err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
c.Set(t.Name(), obj)
}
}
并像这样添加了这个中间件:
apiGroup := router.Group("/api")
{
// other subgroups/endpoints
// ...
subjectGroup := apiGroup.Group("/subject", middleware.Binder(reflect.TypeOf(entity.Subject{})))
}
稍后,在另一个处理程序函数中,假设 GetSubject
,我想访问通过执行 c.MustGet("Subject").(entity.Subject)
传递的主题数据
但这行不通 =(,当我打印 obj
时,它只是一个空界面,我该怎么做?
我设法做了类似的事情!
我创建了以下中间件
var allowedTypes = []binding.Binding{
binding.Query,
binding.Form,
binding.FormPost,
binding.FormMultipart,
}
func Bind(name string, data interface{}, bindingType binding.Binding) gin.HandlerFunc {
return func(ctx *gin.Context) {
ok := false
for _, b := range allowedTypes {
if b == bindingType {
ok = true
}
}
if !ok {
ctx.AbortWithError(
http.StatusInternalServerError,
fmt.Errorf("Bind function only allows %v\n", allowedTypes),
)
}
_ = ctx.MustBindWith(data, bindingType)
ctx.Set(name, data)
}
}
记得在调用中传递一个指向你想要的类型的指针,像这样:
router.GET("/something", Bind("Object", &myObject, binding.Query))
我只限制了一些绑定类型,因为它们允许 ShouldBind
被多次调用,而 JSON
、XML
和其他绑定类型使用 Request
主体。
这样你可以传递多个 Bind 中间件,如果验证失败,它会自动中止 http.StatusBadRequest
我正在尝试编写一个“Binder”中间件,它将使用带有 gin 的结构类型验证任何请求查询 bindings/validators
例如,假设我有一个名为 /api/subject
的端点组,它要求查询字符串具有主题代码和一个 ID,将使用以下结构(称为 entity.Subject
):
type Subject struct {
Code string `binding:"required,alphanum"`
ID string `binding:"required,alphanum,len=4"`
}
这只是一个示例,但我希望能够将任何结构类型传递给此中间件,因为我希望在未来的处理程序上访问查询数据而不必担心查询验证。
所以我尝试了这样的事情:
func Binder(t reflect.Type) gin.HandlerFunc {
return func(c *gin.Context) {
obj := reflect.New(t).Elem().Interface()
if err := c.BindQuery(&obj); err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
c.Set(t.Name(), obj)
}
}
并像这样添加了这个中间件:
apiGroup := router.Group("/api")
{
// other subgroups/endpoints
// ...
subjectGroup := apiGroup.Group("/subject", middleware.Binder(reflect.TypeOf(entity.Subject{})))
}
稍后,在另一个处理程序函数中,假设 GetSubject
,我想访问通过执行 c.MustGet("Subject").(entity.Subject)
但这行不通 =(,当我打印 obj
时,它只是一个空界面,我该怎么做?
我设法做了类似的事情!
我创建了以下中间件
var allowedTypes = []binding.Binding{
binding.Query,
binding.Form,
binding.FormPost,
binding.FormMultipart,
}
func Bind(name string, data interface{}, bindingType binding.Binding) gin.HandlerFunc {
return func(ctx *gin.Context) {
ok := false
for _, b := range allowedTypes {
if b == bindingType {
ok = true
}
}
if !ok {
ctx.AbortWithError(
http.StatusInternalServerError,
fmt.Errorf("Bind function only allows %v\n", allowedTypes),
)
}
_ = ctx.MustBindWith(data, bindingType)
ctx.Set(name, data)
}
}
记得在调用中传递一个指向你想要的类型的指针,像这样:
router.GET("/something", Bind("Object", &myObject, binding.Query))
我只限制了一些绑定类型,因为它们允许 ShouldBind
被多次调用,而 JSON
、XML
和其他绑定类型使用 Request
主体。
这样你可以传递多个 Bind 中间件,如果验证失败,它会自动中止 http.StatusBadRequest