共计 3917 个字符,预计需要花费 10 分钟才能阅读完成。
Gin 框架中,解决 JSON 格局的参数绑定时,默认采纳的规范包 encoding/json
,然而规范包不能满足咱们的一些要求,比方兼容字符串整型、PHP 空数组、工夫格局等。
最简略的形式
开发 API 时,须要用到 ShouldBindJSON 绑定传入的参数到构造体:
// github.com/gin-gonic/gin@v1.6.3/context.go:643
// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
func (c *Context) ShouldBindJSON(obj interface{}) error {return c.ShouldBindWith(obj, binding.JSON)
}
Gin 默认采纳 encoding/json
包:
// github.com/gin-gonic/gin@v1.6.3/internal/json/json.go
// +build !jsoniter
package json
import "encoding/json"
var (
// Marshal is exported by gin/json package.
Marshal = json.Marshal
// Unmarshal is exported by gin/json package.
Unmarshal = json.Unmarshal
// MarshalIndent is exported by gin/json package.
MarshalIndent = json.MarshalIndent
// NewDecoder is exported by gin/json package.
NewDecoder = json.NewDecoder
// NewEncoder is exported by gin/json package.
NewEncoder = json.NewEncoder
)
同时咱们看到还反对了 jsoniter
// github.com/gin-gonic/gin@v1.6.3/internal/json/jsoniter.go
// +build jsoniter
package json
import "github.com/json-iterator/go"
var (
json = jsoniter.ConfigCompatibleWithStandardLibrary
// Marshal is exported by gin/json package.
Marshal = json.Marshal
// Unmarshal is exported by gin/json package.
Unmarshal = json.Unmarshal
// MarshalIndent is exported by gin/json package.
MarshalIndent = json.MarshalIndent
// NewDecoder is exported by gin/json package.
NewDecoder = json.NewDecoder
// NewEncoder is exported by gin/json package.
NewEncoder = json.NewEncoder
)
那咱们怎么能力应用到 jsoniter
呢?源码中曾经明确了编译 tag:
// +build jsoniter
所以,咱们只需在编译时带上这个 tag 就能够了,例如:
go build -tags=jsoniter main.go
// 或者
go run -tags=jsoniter main.go
自定义的形式
Gin 框架反对的 jsoniter
是默认配置 jsoniter.ConfigCompatibleWithStandardLibrary
。当咱们须要其余配置或增加一些自定义扩大(比方工夫解决)时,就好受了。于是咱们就要本人入手了~
打开源码,咱们能看到 binding.JSON
其实应用的是 jsonBinding{}
这个构造体:
// github.com/gin-gonic/gin@v1.6.3/binding/binding.go:73
// These implement the Binding interface and can be used to bind the data
// present in the request to struct instances.
var (JSON = jsonBinding{}
// 其余省略了...
)
打开 jsonBinding
源码看看:
// github.com/gin-gonic/gin@v1.6.3/binding/json.go
type jsonBinding struct{}
func (jsonBinding) Name() string {return "json"}
func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
if req == nil || req.Body == nil {return fmt.Errorf("invalid request")
}
return decodeJSON(req.Body, obj)
}
func (jsonBinding) BindBody(body []byte, obj interface{}) error {return decodeJSON(bytes.NewReader(body), obj)
}
发现实现了 BindingBody
这个接口:
// github.com/gin-gonic/gin@v1.6.3/binding/binding.go:36
// Binding describes the interface which needs to be implemented for binding the
// data present in the request such as JSON request body, query parameters or
// the form POST.
type Binding interface {Name() string
Bind(*http.Request, interface{}) error
}
// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
// but it reads the body from supplied bytes instead of req.Body.
type BindingBody interface {
Binding
BindBody([]byte, interface{}) error
}
那接下来就简略了,咱们只有实现了这个接口即可,例如:
package custom
import (
"bytes"
"fmt"
"io"
"net/http"
jsoniter "github.com/json-iterator/go"
"github.com/gin-gonic/gin/binding"
)
// BindingJSON 替换 Gin 默认的 binding,反对更丰盛 JSON 性能
var BindingJSON = jsonBinding{}
// 能够自定义 jsoniter 配置或者增加插件
var json = jsoniter.ConfigCompatibleWithStandardLibrary
type jsonBinding struct{}
func (jsonBinding) Name() string {return "json"}
func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
if req == nil || req.Body == nil {return fmt.Errorf("invalid request")
}
return decodeJSON(req.Body, obj)
}
func (jsonBinding) BindBody(body []byte, obj interface{}) error {return decodeJSON(bytes.NewReader(body), obj)
}
func decodeJSON(r io.Reader, obj interface{}) error {decoder := json.NewDecoder(r)
if binding.EnableDecoderUseNumber {decoder.UseNumber()
}
if binding.EnableDecoderDisallowUnknownFields {decoder.DisallowUnknownFields()
}
if err := decoder.Decode(obj); err != nil {return err}
return validate(obj)
}
func validate(obj interface{}) error {
if binding.Validator == nil {return nil}
return binding.Validator.ValidateStruct(obj)
}
自定义 jsonBinding
曾经写好了,可应用有 2 种形式:
// binding.JSON 替换成自定义的
ctx.ShouldBindWith(¶ms, binding.JSON)
ctx.ShouldBindBodyWith(¶ms, binding.JSON)
上述自定义的形式,还能够用于其余包,不仅限于 iterator
。从这个方面体现出了 Gin 框架良好的接口设计????
感谢您的浏览,感觉内容不错,点个赞吧 ????
原文地址: https://shockerli.net/post/gin-binding-jsoniter/
正文完