@@ -27,7 +27,7 @@ func main() {
27
27
28
28
...
29
29
30
- // Bind
30
+ // Bind 只做参数绑定
31
31
req = Test{}
32
32
err = ctx.Bind (&req)
33
33
@@ -41,6 +41,22 @@ func main() {
41
41
...
42
42
}
43
43
```
44
+ ### 全部 API
45
+ > hertz version >= v0.7.0
46
+
47
+ | API | 说明 |
48
+ | :--------------------| :----------------------------------------------------------------------------------------------------------------------------------------|
49
+ | ctx.BindAndValidate | 利用下述的 go-tag 进行参数绑定,并在绑定成功后做一次参数校验(如果有校验 tag 的话) |
50
+ | ctx.Bind | 同 "BindAndValidate" 但是不做参数校验 |
51
+ | ctx.BindQuery | 绑定所有 Query 参数,相当于给每一个 field 声明一个 'query' tag,适用于没写 tag 的场景 |
52
+ | ctx.BindHeader | 绑定所有 Header 参数,相当于给每一个 field 声明一个 'header' tag,适用于没写 tag 的场景 |
53
+ | ctx.BindPath | 绑定所有 Path 参数,相当于给每一个 field 声明一个 'path' tag,适用于没写 tag 的场景 |
54
+ | ctx.BindForm | 绑定所有 Form 参数,相当于给每一个 field 声明一个 'form' tag,需要 Content-Type 为: ` application/x-www-form-urlencoded ` /` multipart/form-data ` , 适用于没写 tag 的场景 |
55
+ | ctx.BindJSON | 绑定 JSON Body,调用 json.Unmarshal() 进行反序列化,需要 Body 为 ` application/json ` 格式 |
56
+ | ctx.BindProtobuf | 绑定 Protobuf Body,调用 proto.Unmarshal() 进行反序列化,需要 Body 为 ` application/x-protobuf ` 格式 |
57
+ | ctx.BindByContentType | 根据 Content-Type 来自动选择绑定的方法,其中 "GET" 请求会调用 BindQuery(), 带有 Body 的请求会根据 Content-Type 自动选择 |
58
+ | ctx.Validate | 进行参数校验,需要校验 tag 配合使用(默认校验 tag: vd) |
59
+
44
60
45
61
## 支持的 tag 及参数绑定优先级
46
62
@@ -76,18 +92,172 @@ path > form > query > cookie > header > json > raw_body
76
92
77
93
``` go
78
94
type TagRequiredReq struct {
79
- // 当 JSON 中没有 hertz 字段时,会返回 required 错误:binding: expr_path=hertz, cause=missing required parameter
95
+ // 当 JSON 中没有 hertz 字段时,会返回 required 错误
80
96
Hertz string ` json:"hertz,required"`
81
- // 当 query 和 JSON 中同时没有 kitex 字段时,会返回 required 错误:binding: expr_path=hertz, cause=missing required parameter"
97
+ // 当 query 和 JSON 中同时没有 kitex 字段时,会返回 required 错误
82
98
Kitex string ` query:"kitex,required" json:"kitex,required" `
83
99
}
84
100
```
85
101
86
- ## 常见用法
102
+ ## 常用配置
103
+ > hertz 在 v0.7.0 版本对参数绑定&校验进行重构,重构后配置的行为发生变更,下面将分别介绍<br >
104
+ > 如果还想使用之前的绑定器,目前已把其实现放到了 hertz-contrib 下,可通过自定义 binder 引入
105
+ ### 自定义 binder
106
+ > hertz version >= v0.7.0 支持
107
+
108
+ 需要实现 Binder 接口,并通过配置方式注入到 hertz engine
109
+ ``` go
110
+ type Binder interface {
111
+ Name () string // 绑定器的名字
112
+ // 下面为各种绑定方法
113
+ Bind (*protocol.Request , interface {}, param.Params ) error
114
+ BindAndValidate (*protocol.Request , interface {}, param.Params ) error
115
+ BindQuery (*protocol.Request , interface {}) error
116
+ BindHeader (*protocol.Request , interface {}) error
117
+ BindPath (*protocol.Request , interface {}, param.Params ) error
118
+ BindForm (*protocol.Request , interface {}) error
119
+ BindJSON (*protocol.Request , interface {}) error
120
+ BindProtobuf (*protocol.Request , interface {}) error
121
+ }
122
+ ```
123
+ 注入
124
+ ``` go
125
+
126
+ func main () {
127
+ // 通过配置的方式注入自定义 binder
128
+ h := server.New (server.WithCustomBinder (&mockBinder{}))
129
+ ...
130
+ h.Spin ()
131
+ }
132
+
133
+
134
+ type mockBinder struct {}
135
+
136
+ func (m *mockBinder ) Name () string {
137
+ return " test binder"
138
+ }
139
+
140
+ func (m *mockBinder ) Bind (request *protocol .Request , i interface {}, params param .Params ) error {
141
+ return nil
142
+ }
143
+
144
+ func (m *mockBinder ) BindAndValidate (request *protocol .Request , i interface {}, params param .Params ) error {
145
+ return fmt.Errorf (" test binder" )
146
+ }
147
+
148
+ func (m *mockBinder ) BindQuery (request *protocol .Request , i interface {}) error {
149
+ return nil
150
+ }
151
+
152
+ func (m *mockBinder ) BindHeader (request *protocol .Request , i interface {}) error {
153
+ return nil
154
+ }
155
+
156
+ func (m *mockBinder ) BindPath (request *protocol .Request , i interface {}, params param .Params ) error {
157
+ return nil
158
+ }
159
+
160
+ func (m *mockBinder ) BindForm (request *protocol .Request , i interface {}) error {
161
+ return nil
162
+ }
163
+
164
+ func (m *mockBinder ) BindJSON (request *protocol .Request , i interface {}) error {
165
+ return nil
166
+ }
167
+
168
+ func (m *mockBinder ) BindProtobuf (request *protocol .Request , i interface {}) error {
169
+ return nil
170
+ }
171
+
172
+ ```
173
+
174
+ 目前已拓展的绑定器:
175
+ * bytedance/go-tagexpr: https://github.com/hertz-contrib/binding/tree/main/go_tagexpr
176
+
177
+ ### 自定义 validator
178
+ > hertz version >= v0.7.0 支持
179
+
180
+ 需要实现 Validator 接口,并通过配置方式注入到 hertz engine
181
+ ``` go
182
+ type StructValidator interface {
183
+ ValidateStruct (interface {}) error // 校验函数
184
+ Engine () interface {} // 返回底层的 Validator
185
+ ValidateTag () string // 校验的 tag, 声明校验器使用的 tag
186
+ }
187
+ ```
188
+ 注入
189
+ ``` go
190
+
191
+ func main () {
192
+ // 通过配置的方式注入自定义 binder
193
+ h := server.New (server.WithCustomValidator (&mockValidator{}))
194
+ ...
195
+ h.Spin ()
196
+ }
197
+
198
+ type mockValidator struct {}
199
+
200
+ func (m *mockValidator ) ValidateStruct (interface {}) error {
201
+ return fmt.Errorf (" test mock validator" )
202
+ }
203
+
204
+ func (m *mockValidator ) Engine () interface {} {
205
+ return nil
206
+ }
207
+
208
+ func (m *mockValidator ) ValidateTag () string {
209
+ return " vt"
210
+ }
211
+
212
+ ```
213
+ 目前已拓展的校验器:
214
+ * go-playground/validator: https://github.com/hertz-contrib/binding/tree/main/go_playground
87
215
88
216
### 自定义 bind 和 validate 的 Error
89
217
90
- 绑定参数发生错误和参数校验失败的时候,用户可以自定义的 Error([ demo] ( https://github.com/cloudwego/hertz-examples/tree/main/binding/custom_error ) ),使用方法如下:
218
+ 绑定参数发生错误和参数校验失败的时候,用户可以自定义 Error 的内容,使用方法如下:<br >
219
+ ** hertz version >= v0.7.0**
220
+ > 暂不支持自定义 bind error
221
+
222
+ 自定义错误 error:
223
+ ``` go
224
+ package main
225
+ import (
226
+ " github.com/cloudwego/hertz/pkg/app/server/binding"
227
+ " github.com/cloudwego/hertz/pkg/app/server"
228
+ )
229
+
230
+ type ValidateError struct {
231
+ ErrType , FailField , Msg string
232
+ }
233
+
234
+ // Error implements error interface.
235
+ func (e *ValidateError ) Error () string {
236
+ if e.Msg != " " {
237
+ return e.ErrType + " : expr_path=" + e.FailField + " , cause=" + e.Msg
238
+ }
239
+ return e.ErrType + " : expr_path=" + e.FailField + " , cause=invalid"
240
+ }
241
+
242
+ func main () {
243
+ validateConfig := &binding.ValidateConfig {}
244
+ validateConfig.SetValidatorErrorFactory (func (failField, msg string ) error {
245
+ err := ValidateError{
246
+ ErrType: " validateErr" ,
247
+ FailField: " [validateFailField]: " + failField,
248
+ Msg: " [validateErrMsg]: " + msg,
249
+ }
250
+
251
+ return &err
252
+ })
253
+ h := server.New (server.WithValidateConfig (validateConfig))
254
+ ...
255
+ h.Spin ()
256
+ }
257
+ ```
258
+
259
+ ** hertz version < v0.7.0** <br >
260
+ [ demo] ( https://github.com/cloudwego/hertz-examples/tree/main/binding/custom_error )
91
261
92
262
``` go
93
263
import " github.com/cloudwego/hertz/pkg/app/server/binding"
@@ -142,8 +312,48 @@ func init() {
142
312
```
143
313
144
314
### 自定义类型解析
315
+ 在参数绑定的时候, 针对某些特殊类型, 默认行为无法满足需求, 可使用自定义类型解析来解决, 使用方法如下:<br >
316
+ ** hertz version >= v0.7.0** <br >
317
+ ``` go
318
+ package main
319
+
320
+ import (
321
+ " github.com/cloudwego/hertz/pkg/app/server/binding"
322
+ " github.com/cloudwego/hertz/pkg/app/server"
323
+ )
324
+
325
+ type Nested struct {
326
+ B string
327
+ C string
328
+ }
329
+
330
+ type TestBind struct {
331
+ A Nested ` query:"a,required"`
332
+ }
145
333
146
- 在参数绑定的时候,所有的 request 参数都是 ` string ` 或者 ` []string ` ;当有一些 field 的类型为非基础类型或者无法直接通过 ` string ` 转换,则可以自定义类型解析([ demo] ( https://github.com/cloudwego/hertz-examples/tree/main/binding/custom_type_resolve ) )。使用方法如下:
334
+ func main () {
335
+ bindConfig := &binding.BindConfig {}
336
+ // v0.7.0 重构后,在原基础上增加了请求 Request 内容以及路由参数,可方便用户更加灵活的自定义类型解析
337
+ bindConfig.MustRegTypeUnmarshal (reflect.TypeOf (Nested{}), func (req *protocol.Request , params param.Params , text string ) (reflect.Value , error ) {
338
+ if text == " " {
339
+ return reflect.ValueOf (Nested{}), nil
340
+ }
341
+ val := Nested{
342
+ B: text[:5 ],
343
+ C: text[5 :],
344
+ }
345
+ // 此外,也可以利用 req, params 来获取其他参数进行参数绑定
346
+ return reflect.ValueOf (val), nil
347
+ })
348
+ h := server.New (server.WithBindConfig (bindConfig))
349
+
350
+ ...
351
+ h.Spin ()
352
+ }
353
+ ```
354
+ ** hertz version < v0.7.0** <br >
355
+
356
+ [ demo] ( https://github.com/cloudwego/hertz-examples/tree/main/binding/custom_type_resolve )
147
357
148
358
``` go
149
359
import " github.com/cloudwego/hertz/pkg/app/server/binding"
@@ -172,9 +382,39 @@ func init() {
172
382
```
173
383
174
384
### 自定义验证函数
385
+ 可以通过注册自定义验证函数,在'vd'注解中实现复杂的验证逻辑:<br >
386
+ ** hertz version >= v0.7.0** <br >
387
+ ``` go
388
+ package main
175
389
176
- 可以通过注册自定义验证函数,在'vd'注解中实现复杂的验证逻辑([ demo] ( https://github.com/cloudwego/hertz-examples/tree/main/binding/custom_validate_func ) ),使用方法如下:
390
+ import (
391
+ " github.com/cloudwego/hertz/pkg/app/server/binding"
392
+ " github.com/cloudwego/hertz/pkg/app/server"
393
+ )
177
394
395
+ func main () {
396
+ type Req struct {
397
+ A int ` query:"a" vd:"test($)"`
398
+ }
399
+ validateConfig := &binding.ValidateConfig {}
400
+ validateConfig.MustRegValidateFunc (" test" , func (args ...interface {}) error {
401
+ if len (args) != 1 {
402
+ return fmt.Errorf (" the args must be one" )
403
+ }
404
+ s , _ := args[0 ].(string )
405
+ if s == " 123" {
406
+ return fmt.Errorf (" the args can not be 123" )
407
+ }
408
+ return nil
409
+ })
410
+ h := server.New (server.WithValidateConfig (validateConfig))
411
+ ...
412
+ h.Spin ()
413
+ }
414
+ ```
415
+
416
+ ** hertz version < v0.7.0** <br >
417
+ [ demo] ( https://github.com/cloudwego/hertz-examples/tree/main/binding/custom_validate_func )
178
418
``` go
179
419
import " github.com/cloudwego/hertz/pkg/app/server/binding"
180
420
@@ -194,8 +434,25 @@ func init() {
194
434
195
435
### 配置 looseZero
196
436
197
- 在一些场景下,前端有时候传来的信息只有 key 没有 value,这会导致绑定数值类型的时候,会报错 ` cause=parameter type does not match binding data ` 。
198
- 这时需要配置 looseZero 模式([ demo] ( https://github.com/cloudwego/hertz-examples/tree/main/binding/loose_zero ) ),使用方法如下:
437
+ 在一些场景下,前端有时候传来的信息只有 key 没有 value,这会导致绑定数值类型的时候报错;这时需要配置 looseZero 模式,使用方法如下:
438
+ ** hertz version >= v0.7.0** <br >
439
+ ``` go
440
+ package main
441
+
442
+ import (
443
+ " github.com/cloudwego/hertz/pkg/app/server/binding"
444
+ " github.com/cloudwego/hertz/pkg/app/server"
445
+ )
446
+
447
+ func main () {
448
+ bindConfig := binding.NewBindConfig ()
449
+ bindConfig.LooseZeroMode = true
450
+ h := server.New (server.WithBindConfig (bindConfig))
451
+ ...
452
+ h.Spin ()
453
+ }
454
+ ```
455
+ ** hertz version < v0.7.0** <br >
199
456
200
457
``` go
201
458
import " github.com/cloudwego/hertz/pkg/app/server/binding"
@@ -207,9 +464,24 @@ func init() {
207
464
```
208
465
209
466
### 配置其他 json unmarshal 库
467
+ 在绑定参数的时候,如果请求体为 json,会进行一次 json 的 unmarshal,如果用户需要使用特定的 json 库可以自己配置(hertz 默认使用开源 json 库 [ sonic] ( https://github.com/bytedance/sonic ) )。使用方法如下:<br >
468
+ ** hertz version >= v0.7.0** <br >
469
+ ``` go
470
+ import (
471
+ " github.com/cloudwego/hertz/pkg/app/server/binding"
472
+ " github.com/cloudwego/hertz/pkg/app/server"
473
+ )
210
474
211
- 在绑定参数的时候,如果请求体为 json,会进行一次 json 的 unmarshal,如果用户需要使用特定的 json 库可以自己配置(hertz 默认使用开源 json 库 [ sonic] ( https://github.com/bytedance/sonic ) )。使用方法如下:
212
-
475
+ func main () {
476
+ bindConfig := binding.NewBindConfig ()
477
+ bindConfig.UseStdJSONUnmarshaler () // 使用标准库, hertz 默认使用 sonic 作为 json 序列化/反序列化器
478
+ // bindConfig.UseThirdPartyJSONUnmarshaler(sonic.Unmarshal) // 使用 sonic 作为 json 序列化/反序列化器
479
+ h := server.New (server.WithBindConfig (bindConfig))
480
+ ...
481
+ h.Spin ()
482
+ }
483
+ ```
484
+ ** hertz version < v0.7.0** <br >
213
485
``` go
214
486
import " github.com/cloudwego/hertz/pkg/app/server/binding"
215
487
@@ -226,6 +498,7 @@ func init() {
226
498
```
227
499
228
500
### 设置默认值
501
+ > 重构前后使用方式都一样
229
502
230
503
参数支持 "default" tag 进行默认值的配置,使用方法如下:
231
504
@@ -237,6 +510,7 @@ type UserInfoResponse struct {
237
510
```
238
511
239
512
### 绑定文件
513
+ > 重构前后使用方式一样,IDL 场景不支持文件绑定
240
514
241
515
参数绑定支持绑定文件,使用方法如下:
242
516
0 commit comments