init: 通用库抽离——httpx/logger/wsc/wscclient/jwtx(合并分叉副本); 顶层包布局; module path git.zeroonesoft.cn/golib/zogo
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
package httpx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
// bindingValidator 与 gin 同源: 校验 struct 的 binding tag
|
||||
var bindingValidator = validator.New(validator.WithRequiredStructEnabled())
|
||||
|
||||
func init() {
|
||||
bindingValidator.SetTagName("binding")
|
||||
// 关闭 gin 内置校验 (ShouldBindQuery/Header/JSON 内部各自 validate, 会使 json 字段的
|
||||
// required 在 query 阶段误报)。校验统一由 Parse 末尾的 bindingValidator 收口。
|
||||
binding.Validator = nil
|
||||
}
|
||||
|
||||
// Parse 按统一顺序绑定请求参数: uri → query → header → json body。
|
||||
// 各来源只做绑定不做校验, 全部绑定完后统一跑 binding 校验。
|
||||
// (修复: gin 的 ShouldBindQuery 内部即执行校验, 会使 json 字段的 required 在 query 阶段误报)
|
||||
func Parse(c *gin.Context, v any) error {
|
||||
if err := parseUri(c, v); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := parseQuery(c, v); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := parseHeader(c, v); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := parseJSON(c, v); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(c, v)
|
||||
}
|
||||
|
||||
func parseUri(c *gin.Context, v any) error {
|
||||
if _, ok := c.Params.Get("id"); ok {
|
||||
return c.ShouldBindUri(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseQuery(c *gin.Context, v any) error {
|
||||
return c.ShouldBindQuery(v)
|
||||
}
|
||||
|
||||
func parseHeader(c *gin.Context, v any) error {
|
||||
return c.ShouldBindHeader(v)
|
||||
}
|
||||
|
||||
// parseJSON 直接解码 body, 不触发 gin 内部校验 (校验统一在 Parse 末尾)
|
||||
func parseJSON(c *gin.Context, v any) error {
|
||||
if c.Request == nil || c.Request.Body == nil || c.Request.ContentLength == 0 {
|
||||
return nil
|
||||
}
|
||||
return json.NewDecoder(c.Request.Body).Decode(v)
|
||||
}
|
||||
|
||||
// Validator 请求结构体可实现此接口做自定义校验, 在 binding 校验之前调用
|
||||
type Validator interface {
|
||||
Validate() error
|
||||
}
|
||||
|
||||
func validate(c *gin.Context, v any) error {
|
||||
if vv, ok := v.(Validator); ok {
|
||||
if err := vv.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return bindingValidator.Struct(v)
|
||||
}
|
||||
Reference in New Issue
Block a user