教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Gin 框架绑定 JSON 参数使用 jsoniter

Gin 框架绑定 JSON 参数使用 jsoniter

发布时间:2022-01-06   编辑:jiaochengji.com
教程集为您提供Gin 框架绑定 JSON 参数使用 jsoniter等资源,欢迎您收藏本站,我们将为您提供最新的Gin 框架绑定 JSON 参数使用 jsoniter资源

Gin 框架中,处理 JSON 格式的参数绑定时,默认采用的标准包 <code>encoding/json</code>,然而标准包不能满足我们的一些要求,比如兼容字符串整型、PHP空数组、时间格式等。

<h2>最简单的方式</h2>

开发 API 时,需要用到 ShouldBindJSON 绑定传入的参数到结构体:

<pre><code class="go">// 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) }</code></pre>

Gin 默认采用 <code>encoding/json</code> 包:

<pre><code class="go">// 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 )</code></pre>

同时我们看到还支持了 <code>jsoniter</code>

<pre><code class="go">// 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 )</code></pre>

那我们怎么才能使用到 <code>jsoniter</code> 呢?源码中已经明确了编译tag:

<pre><code class="go">// build jsoniter</code></pre>

所以,我们只需在编译时带上这个 tag 就可以了,例如:

<pre><code class="sh">go build -tags=jsoniter main.go // 或者 go run -tags=jsoniter main.go</code></pre><h2>自定义的方式</h2>

Gin 框架支持的 <code>jsoniter</code> 是默认配置 <code>jsoniter.ConfigCompatibleWithStandardLibrary</code>。当我们需要其他配置或添加一些自定义扩展(比如时间处理)时,就难受了。于是我们就要自己动手了~

翻开源码,我们能看到 <code>binding.JSON</code> 其实使用的是 <code>jsonBinding{}</code> 这个结构体:

<pre><code class="go">// 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{} // 其他省略了... )</code></pre>

翻开 <code>jsonBinding</code> 源码看看:

<pre><code class="go">// 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) }</code></pre>

发现实现了 <code>BindingBody</code> 这个接口:

<pre><code class="go">// 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 }</code></pre>

那接下来就简单了,我们只要实现了这个接口即可,例如:

<pre><code class="go">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) }</code></pre>

自定义 <code>jsonBinding</code> 已经写好了,可使用有2种方式:

<pre><code class="go">// binding.JSON 替换成自定义的 ctx.ShouldBindWith(&params, binding.JSON) ctx.ShouldBindBodyWith(&params, binding.JSON)</code></pre>

上述自定义的方式,还可以用于其他包,不仅限于 <code>iterator</code>。从这个方面体现出了 Gin 框架良好的接口设计

您可能感兴趣的文章:
Gin 框架绑定 JSON 参数使用 jsoniter
Go语言网络编程入门不走弯路最佳案例(写Api接口)
gin定义统一处理错误
Golang pprof 性能分析与火焰图
golang 上传文件(包括 gin 实现)
Golang Gin 实战(六)| 获取Form表单参数和原理分析
20 个好用的 Go 语言微服务开发框架
想系统学习GO语言(Golang
使用 golang的gin框架实现,文件上传
20 个有用的 Go 语言微服务开发框架

[关闭]
~ ~