问题描述
我正在尝试编写一个“Binder”中间件,它将使用带有 gin 绑定/验证器的结构类型来验证任何请求查询
例如,假设我有一个名为 /api/subject
的端点组,它要求查询字符串具有一个主题代码和一个 ID,该 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
时,它只是一个空界面,我该怎么做?
解决方法
我设法做了类似的事情!
我创建了以下中间件
jQuery('.collapse').on('show.bs.collapse',function () {
jQuery('.collapse').removeClass('in');
});
记得在调用中传递一个指向你想要的类型的指针,就像这样:
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
主体。>
通过这种方式,您可以传递多个 Bind 中间件,如果验证失败,它会自动中止 Request