From c71b4aabbb5a6097adf349e10a81aebdeec95753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Mon, 15 Dec 2025 12:33:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96Body=E5=8F=82?= =?UTF-8?q?=E6=95=B0,=E6=94=AF=E6=8C=81any=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- httpclient/define/request.go | 16 ++++++++-------- httpclient/resty.go | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/httpclient/define/request.go b/httpclient/define/request.go index 639835a..2418eb0 100644 --- a/httpclient/define/request.go +++ b/httpclient/define/request.go @@ -20,21 +20,21 @@ import ( // Date : 17:10 2024/5/24 type Request struct { Ctx context.Context `json:"-"` // 请求上下文 - PathParam map[string]string `json:"path_param"` // 替换url中的占位符 - Body map[string]any `json:"body"` // 请求Body - Header map[string]any `json:"header"` // 请求Header - Cookie map[string]any `json:"cookie"` // 请求Cookie - Query map[string]any `json:"query"` // 请求query + PathParam map[string]string `json:"path_param"` // 替换 url 中的占位符 + Body any `json:"body"` // 请求 Body + Header map[string]any `json:"header"` // 请求 Header + Cookie map[string]any `json:"cookie"` // 请求 Cookie + Query map[string]any `json:"query"` // 请求 query Static map[string]map[string]any `json:"static"` // 静态参数: location => valName => val - FullUrl string `json:"full_url"` // 完整的请求URL + FullUrl string `json:"full_url"` // 完整的请求 URL ContentType string `json:"content_type"` // 请求类型 Method string `json:"method"` // 请求方法 DataField string `json:"data_field"` // 数据字段,// 数据字段 BODY_ROOT 代表整个BODY 都是带解析数据 CodeField string `json:"code_field"` // 业务状态码字段 CodeLocation string `json:"code_location"` // 业务状态码位置 - MessageField string `json:"message_field"` // code描述字段 + MessageField string `json:"message_field"` // code 描述字段 MessageFieldLocation string `json:"message_field_location"` // code 描述字段位置 - DataReceiver any `json:"-"` // 响应data部分数据解析 + DataReceiver any `json:"-"` // 响应 data 部分数据解析 SuccessHttpCodeList []int `json:"success_http_code_list"` // 哪些http状态码视为成功, 不配置, 默认2xx SuccessCodeList []string `json:"success_code_list"` // 哪些业务状态码视为成功 ConnectTimeout int64 `json:"connect_timeout"` // 连接超时时间: ms diff --git a/httpclient/resty.go b/httpclient/resty.go index f570053..16ec3d2 100644 --- a/httpclient/resty.go +++ b/httpclient/resty.go @@ -10,6 +10,7 @@ package httpclient import ( "errors" "fmt" + "io" "net/http" "net/textproto" "strings" @@ -17,6 +18,7 @@ import ( "git.zhangdeman.cn/zhangdeman/consts" "git.zhangdeman.cn/zhangdeman/network/httpclient/define" requestBoodyWriter "git.zhangdeman.cn/zhangdeman/network/httpclient/implement/request" + "git.zhangdeman.cn/zhangdeman/serialize" "git.zhangdeman.cn/zhangdeman/wrapper/op_any" "resty.dev/v3" ) @@ -42,12 +44,32 @@ func initRequestConfig(reqConfig *define.Request) { reqConfig.PathParam = map[string]string{} } + // body 转为 map + bodyMap := make(map[string]any) + if nil == reqConfig.Body { + bodyMap = map[string]any{} + } else { + switch val := reqConfig.Body.(type) { + case map[string]any: + bodyMap = val + case struct{}, *struct{}: + serialize.JSON.TransitionIgnoreError(reqConfig.Body, &bodyMap) + case string: + serialize.JSON.UnmarshalWithNumberIgnoreError([]byte(val), &bodyMap) + case []byte: + serialize.JSON.UnmarshalWithNumberIgnoreError(val, &bodyMap) + case io.Reader: + dataContent, _ := io.ReadAll(val) + serialize.JSON.UnmarshalWithNumberIgnoreError(dataContent, &bodyMap) + } + } + // 合并静态参数, 传入参数与静态参数存在相同参数, 以静态参数为准 for loc, paramTable := range reqConfig.Static { switch strings.ToUpper(loc) { case consts.RequestDataLocationBody.String(): for name, val := range paramTable { - reqConfig.Body[name] = val + bodyMap[name] = val } case consts.RequestDataLocationQuery.String(): for name, val := range paramTable { @@ -68,6 +90,9 @@ func initRequestConfig(reqConfig *define.Request) { } } + // 重置 Body + reqConfig.Body = bodyMap + formatHeader(reqConfig) } @@ -78,6 +103,9 @@ func initRequestConfig(reqConfig *define.Request) { // Date : 15:00 2024/5/31 func NewRestyClient(reqConfig *define.Request, reqOption *RequestOption) (*resty.Client, *resty.Request, error) { client := resty.New() + defer func() { + _ = client.Close() + }() request := client.R() if nil == reqConfig { return nil, nil, errors.New("request config is nil") @@ -149,11 +177,11 @@ func setRestyBody(reqConfig *define.Request, requestOption *RequestOption, reque } if nil != requestOption && nil != requestOption.RequestBodyWrite { // 外部传入的实现 - requestOption.RequestBodyWrite.Write(request, reqConfig.Body) + requestOption.RequestBodyWrite.Write(request, reqConfig.Body.(map[string]any)) return nil } // 外部没传入, 使用内置实现, 内置默认实现支持: xml/json/form, 如需其他, 自行扩展 - return requestBoodyWriter.WriteBody(reqConfig.ContentType, request, reqConfig.Body) + return requestBoodyWriter.WriteBody(reqConfig.ContentType, request, reqConfig.Body.(map[string]any)) } // formatHeader 格式化header