升级body解析
This commit is contained in:
parent
146fbaf878
commit
2aa8e86917
4
go.mod
4
go.mod
@ -10,7 +10,7 @@ require (
|
||||
git.zhangdeman.cn/zhangdeman/exception v0.0.0-20250207091724-ca151fbc1f06
|
||||
git.zhangdeman.cn/zhangdeman/logger v0.0.0-20241125083316-eab7bab9d7ad
|
||||
git.zhangdeman.cn/zhangdeman/network v0.0.0-20230925112156-f0eb86dd2442
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250428041157-135850ee8a58
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250504055908-8d68e6106ea9
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/go-playground/validator/v10 v10.26.0
|
||||
@ -34,7 +34,7 @@ require (
|
||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||
github.com/gin-contrib/pprof v1.5.2 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
|
6
go.sum
6
go.sum
@ -30,6 +30,10 @@ git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd h1:q7G
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd/go.mod h1:+D6uPSljwHywjVY5WSBY4TRVMj26TN5f5cFGEYMldjs=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250428041157-135850ee8a58 h1:fTkmucGaUoKocoX+ASM4AnwsAVJOtOOLUFSqA+uwVzg=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250428041157-135850ee8a58/go.mod h1:Ig3GZC2hJDkQp7F8Tm53GvMWLh9bdbbauow/vxGO4YA=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250503114548-0c3d7b7e92eb h1:2kWDxCHTFfFTb4aPcM3wL/wYfsKHy3XdtEutl+a64lM=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250503114548-0c3d7b7e92eb/go.mod h1:iDz8l9mwNbP3nrahmg6lyzAgqH5uBqQBaRHfub1C2Rw=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250504055908-8d68e6106ea9 h1:/GLQaFoLb+ciHOtAS2BIyPNnf4O5ME3AC5PUaJY9kfs=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250504055908-8d68e6106ea9/go.mod h1:ABJ655C5QenQNOzf7LjCe4sSB52CXvaWLX2Zg4uwDJY=
|
||||
git.zhangdeman.cn/zhangdeman/trace v0.0.0-20250412104923-c1ecb1bfe8d5 h1:dD1Q/MIrRmIhKqfYPH+y167ca9CKwTPuQt3c1hXWGJ8=
|
||||
git.zhangdeman.cn/zhangdeman/trace v0.0.0-20250412104923-c1ecb1bfe8d5/go.mod h1:PB486NC82nuvn5yi+U2i48ogX/9EAETWAHd8O9TwY9k=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e h1:Q973S6CcWr1ICZhFI1STFOJ+KUImCl2BaIXm6YppBqI=
|
||||
@ -67,6 +71,8 @@ github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbY
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
||||
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
|
||||
github.com/gin-contrib/pprof v1.5.2 h1:Kcq5W2bA2PBcVtF0MqkQjpvCpwJr+pd7zxcQh2csg7E=
|
||||
|
@ -7,20 +7,12 @@
|
||||
// Date : 2024-10-22 16:38
|
||||
package abstract
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// RequestBodyParseAdaptor 解析请求body的接口适配器约束
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:39 2024/10/22
|
||||
type RequestBodyParseAdaptor interface {
|
||||
// Parse 解析Body数据,解析结果会反序列化至 receiver , 同时, 会以 map 结构返回
|
||||
Parse(ctx *gin.Context, receiver any) ([]byte, error)
|
||||
// Unmarshal 自定义反序列化的方法, 为 nil 则使用内置的序列化方式
|
||||
Unmarshal() func(sourceData []byte, receiver any) error
|
||||
// ContentType 当前适配器用与解析何种type
|
||||
ContentType() string
|
||||
Unmarshal(sourceData []byte, receiver any) error
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
// Package parse_body ...
|
||||
//
|
||||
// Description : parse_body ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-10-22 16:51
|
||||
package parse_body
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
)
|
||||
|
||||
type base struct {
|
||||
}
|
||||
|
||||
// Unmarshal 反序列化方法,可以不指定
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:54 2024/10/22
|
||||
func (b base) Unmarshal() func(sourceData []byte, receiver any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DoParse 解析
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:08 2024/10/22
|
||||
func (b base) DoParse(ctx *gin.Context, receiver any, unmarshalFunc func(sourceData []byte, receiver any) error) ([]byte, error) {
|
||||
data, err := io.ReadAll(ctx.Request.Body)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
ctx.Request.Body = io.NopCloser(bytes.NewBuffer(data))
|
||||
if nil == unmarshalFunc || nil == receiver {
|
||||
return data, nil
|
||||
}
|
||||
if err := unmarshalFunc(data, receiver); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
return data, err
|
||||
}
|
@ -8,9 +8,12 @@
|
||||
package parse_body
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"git.zhangdeman.cn/zhangdeman/gin/request/abstract"
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -19,14 +22,12 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
adaptorList := []abstract.RequestBodyParseAdaptor{
|
||||
JsonAdaptor{},
|
||||
FormUrlEncode{},
|
||||
XmlAdaptor{},
|
||||
}
|
||||
for _, itemAdaptor := range adaptorList {
|
||||
Register(itemAdaptor)
|
||||
}
|
||||
requestBodyParseAdaptorTable["xml"] = serialize.Xml
|
||||
requestBodyParseAdaptorTable["ini"] = serialize.Ini
|
||||
requestBodyParseAdaptorTable["yml"] = serialize.Yml
|
||||
requestBodyParseAdaptorTable["yaml"] = serialize.Yml
|
||||
requestBodyParseAdaptorTable["json"] = serialize.JSON
|
||||
requestBodyParseAdaptorTable["x-www-form-urlencoded"] = serialize.JSON
|
||||
}
|
||||
|
||||
// Register 注册适配器实例
|
||||
@ -34,27 +35,39 @@ func init() {
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:45 2024/10/22
|
||||
func Register(adaptor abstract.RequestBodyParseAdaptor) {
|
||||
func Register(requestType string, adaptor abstract.RequestBodyParseAdaptor) {
|
||||
if nil == adaptor {
|
||||
return
|
||||
}
|
||||
requestBodyParseAdaptorTable[adaptor.ContentType()] = adaptor
|
||||
requestBodyParseAdaptorTable[requestType] = adaptor
|
||||
}
|
||||
|
||||
// Execute 解析请求BODY数据
|
||||
func Execute(ctx *gin.Context, receiver any) ([]byte, error) {
|
||||
contentType := strings.ToLower(strings.ReplaceAll(ctx.ContentType(), " ", ""))
|
||||
// 裁剪出真实的类型,之所以截取,是因为 content_type 中可能还包含编码信息, 如 : application/json;charset=utf8
|
||||
if len(contentType) == 0 {
|
||||
return nil, errors.New("content_type is empty")
|
||||
}
|
||||
// 裁剪出真实的类型,之所以截取,是因为 content_type 中可能还包含编码信息, 如 : application/json;chaset=utf8
|
||||
contentTypeArr := strings.Split(contentType, ";")
|
||||
contentTypeFormatArr := strings.Split(contentTypeArr[0], "/")
|
||||
if len(contentTypeFormatArr) != 2 {
|
||||
return nil, errors.New(contentType + " : content_type format error")
|
||||
}
|
||||
// 裁剪出真实的类型,之所以截取,是因为 content_type 中可能还包含编码信息, 如 : application/json;charset=utf8
|
||||
contentType = contentTypeArr[0]
|
||||
if _, exist := requestBodyParseAdaptorTable[contentType]; !exist {
|
||||
return nil, errors.New(contentType + " : adaptor not found")
|
||||
}
|
||||
if parseResult, err := requestBodyParseAdaptorTable[contentType].Parse(ctx, receiver); nil != err {
|
||||
bodyData, err := ReadBody(ctx)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
} else {
|
||||
return parseResult, err
|
||||
}
|
||||
if err = requestBodyParseAdaptorTable[contentType].Unmarshal(bodyData, receiver); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
byteData := serialize.JSON.MarshalForByteIgnoreError(receiver)
|
||||
return byteData, nil
|
||||
}
|
||||
|
||||
// ExecuteForMap 高层级包装,表单解析为map
|
||||
@ -68,3 +81,34 @@ func ExecuteForMap(ctx *gin.Context) (map[string]any, error) {
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ReadBody 读取请求Body
|
||||
func ReadBody(ctx *gin.Context) ([]byte, error) {
|
||||
var (
|
||||
data []byte
|
||||
err error
|
||||
)
|
||||
// 判断form url encode
|
||||
if strings.Contains(ctx.ContentType(), "x-www-form-urlencoded") {
|
||||
if err = ctx.Request.ParseForm(); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
body := map[string]any{}
|
||||
for paramName, itemParam := range ctx.Request.PostForm {
|
||||
if len(itemParam) > 0 {
|
||||
body[paramName] = itemParam[0]
|
||||
} else {
|
||||
body[paramName] = ""
|
||||
}
|
||||
}
|
||||
return serialize.JSON.MarshalForByteIgnoreError(body), nil
|
||||
}
|
||||
|
||||
// 读取Body信息
|
||||
if data, err = io.ReadAll(ctx.Request.Body); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
// 重置Body信息
|
||||
ctx.Request.Body = io.NopCloser(bytes.NewBuffer(data))
|
||||
return data, nil
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
// Package parse_body ...
|
||||
//
|
||||
// Description : parse_body ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-10-22 16:43
|
||||
package parse_body
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"git.zhangdeman.cn/zhangdeman/consts"
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type FormUrlEncode struct {
|
||||
base
|
||||
}
|
||||
|
||||
func (f FormUrlEncode) Parse(ctx *gin.Context, receiver any) ([]byte, error) {
|
||||
if err := ctx.Request.ParseForm(); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
body := map[string]string{}
|
||||
for paramName, itemParam := range ctx.Request.PostForm {
|
||||
if len(itemParam) > 0 {
|
||||
body[paramName] = itemParam[0]
|
||||
} else {
|
||||
body[paramName] = ""
|
||||
}
|
||||
}
|
||||
byteData, _ := json.Marshal(body)
|
||||
if nil != receiver {
|
||||
if err := serialize.JSON.UnmarshalWithNumber(byteData, receiver); nil != receiver {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return byteData, nil
|
||||
}
|
||||
|
||||
func (f FormUrlEncode) ContentType() string {
|
||||
return consts.MimeTypeXWWWFormUrlencoded
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
// Package parse_body ...
|
||||
//
|
||||
// Description : parse_body ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-10-22 16:42
|
||||
package parse_body
|
||||
|
||||
import (
|
||||
"git.zhangdeman.cn/zhangdeman/consts"
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type JsonAdaptor struct {
|
||||
base
|
||||
}
|
||||
|
||||
// Parse 解析json请求体
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:13 2024/10/22
|
||||
func (j JsonAdaptor) Parse(ctx *gin.Context, receiver any) ([]byte, error) {
|
||||
unmarshalFunc := j.Unmarshal()
|
||||
if nil == unmarshalFunc {
|
||||
unmarshalFunc = serialize.JSON.UnmarshalWithNumber
|
||||
}
|
||||
return j.DoParse(ctx, receiver, unmarshalFunc)
|
||||
}
|
||||
|
||||
// Unmarshal 指定解析方法
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:56 2024/10/22
|
||||
func (j JsonAdaptor) Unmarshal() func(sourceData []byte, receiver any) error {
|
||||
return serialize.JSON.UnmarshalWithNumber
|
||||
}
|
||||
|
||||
// ContentType 请求类型固定返回json
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:59 2024/10/22
|
||||
func (j JsonAdaptor) ContentType() string {
|
||||
return consts.MimeTypeJson
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
// Package parse_body ...
|
||||
//
|
||||
// Description : parse_body ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-10-22 16:42
|
||||
package parse_body
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"git.zhangdeman.cn/zhangdeman/consts"
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sbabiv/xml2map"
|
||||
)
|
||||
|
||||
type XmlAdaptor struct {
|
||||
base
|
||||
}
|
||||
|
||||
func (x XmlAdaptor) Parse(ctx *gin.Context, receiver any) ([]byte, error) {
|
||||
unmarshalFunc := x.Unmarshal()
|
||||
if nil == unmarshalFunc {
|
||||
unmarshalFunc = serialize.Xml.UnmarshalWithNumber
|
||||
}
|
||||
return x.DoParse(ctx, receiver, unmarshalFunc)
|
||||
}
|
||||
|
||||
func (x XmlAdaptor) Unmarshal() func(sourceData []byte, receiver any) error {
|
||||
return func(sourceData []byte, receiver any) error {
|
||||
res, err := xml2map.NewDecoder(bytes.NewReader(sourceData)).Decode()
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
return serialize.JSON.Transition(res, receiver)
|
||||
}
|
||||
}
|
||||
|
||||
func (x XmlAdaptor) ContentType() string {
|
||||
return consts.MimeTypeXml
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
// Package parse_body ...
|
||||
//
|
||||
// Description : parse_body ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-10-22 16:43
|
||||
package parse_body
|
Loading…
x
Reference in New Issue
Block a user