支持自适应请求类型, 根据不同请求类型设置正确Body格式
This commit is contained in:
parent
1abe6c1c29
commit
1403693fda
16
httpclient/abstract/IRequestBodyWrite.go
Normal file
16
httpclient/abstract/IRequestBodyWrite.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Package abstract ...
|
||||||
|
//
|
||||||
|
// Description : abstract ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 2025-05-08 14:18
|
||||||
|
package abstract
|
||||||
|
|
||||||
|
import "resty.dev/v3"
|
||||||
|
|
||||||
|
// IRequestBodyWrite 请求信息写入Body的接口约束
|
||||||
|
type IRequestBodyWrite interface {
|
||||||
|
// Write 写入请求Body
|
||||||
|
Write(request *resty.Request, bodyData map[string]any) error
|
||||||
|
}
|
@ -99,7 +99,13 @@ func NewHttpClient(reqConfig *define.Request, reqOption *RequestOption) (*HttpCl
|
|||||||
if ua, exist := reqConfig.Header[consts.HeaderKeyUserAgent.String()]; !exist || nil == ua || fmt.Sprintf("%v", ua) == "" {
|
if ua, exist := reqConfig.Header[consts.HeaderKeyUserAgent.String()]; !exist || nil == ua || fmt.Sprintf("%v", ua) == "" {
|
||||||
reqConfig.Header[consts.HeaderKeyUserAgent.String()] = "resty-v3@network/httpclient"
|
reqConfig.Header[consts.HeaderKeyUserAgent.String()] = "resty-v3@network/httpclient"
|
||||||
}
|
}
|
||||||
restyClient, restyRequest := NewRestyClient(reqConfig, reqOption)
|
restyClient, restyRequest, err := NewRestyClient(reqConfig, reqOption)
|
||||||
|
if nil != err {
|
||||||
|
if nil != restyClient {
|
||||||
|
_ = restyClient.Close()
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
defer restyClient.Close()
|
defer restyClient.Close()
|
||||||
|
|
||||||
hc := &HttpClient{
|
hc := &HttpClient{
|
||||||
|
55
httpclient/implement/request/write_body.go
Normal file
55
httpclient/implement/request/write_body.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Package request ...
|
||||||
|
//
|
||||||
|
// Description : request ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 2025-05-08 14:21
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/network/httpclient/abstract"
|
||||||
|
"resty.dev/v3"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// WriteBodyInstanceTable 请求类型 => 请求类型写入的实现
|
||||||
|
WriteBodyInstanceTable = map[string]abstract.IRequestBodyWrite{
|
||||||
|
"json": &WriteJson{},
|
||||||
|
"xml": nil,
|
||||||
|
"x-www-form-urlencoded": &WriteForm{},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetWriteBodyInstance(cType string, instance abstract.IRequestBodyWrite) {
|
||||||
|
WriteBodyInstanceTable[cType] = instance
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteWriteBodyInstance(cType string) {
|
||||||
|
delete(WriteBodyInstanceTable, cType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBody 数据写入body
|
||||||
|
func WriteBody(contentType string, request *resty.Request, bodyData map[string]any) error {
|
||||||
|
if nil == bodyData {
|
||||||
|
// body为nil, 无需写入, 否则即使为空map也要正常写入
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if nil == request {
|
||||||
|
return errors.New("request is nil")
|
||||||
|
}
|
||||||
|
contentType = strings.TrimSpace(strings.Split(contentType, ";")[0])
|
||||||
|
if len(contentType) == 0 {
|
||||||
|
return errors.New("contentType is empty or invalid")
|
||||||
|
}
|
||||||
|
contentTypeArr := strings.Split(contentType, "/")
|
||||||
|
realType := contentTypeArr[len(contentTypeArr)-1]
|
||||||
|
writeInstance, ok := WriteBodyInstanceTable[realType]
|
||||||
|
if !ok || writeInstance == nil {
|
||||||
|
return errors.New(realType + " is not support, writeInstance is nil")
|
||||||
|
}
|
||||||
|
writeInstance.Write(request, bodyData)
|
||||||
|
return nil
|
||||||
|
}
|
33
httpclient/implement/request/write_form.go
Normal file
33
httpclient/implement/request/write_form.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Package request ...
|
||||||
|
//
|
||||||
|
// Description : request ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 2025-05-08 14:39
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
"resty.dev/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WriteForm application/x-www-form-urlencoded 实现
|
||||||
|
type WriteForm struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WriteForm) Write(request *resty.Request, bodyData map[string]any) error {
|
||||||
|
if len(bodyData) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
bodyStr := serialize.JSON.MarshalForStringIgnoreError(bodyData)
|
||||||
|
formatBodyData := map[string]string{}
|
||||||
|
jsonObj := gjson.Parse(bodyStr)
|
||||||
|
jsonObj.ForEach(func(key, value gjson.Result) bool {
|
||||||
|
formatBodyData[key.String()] = value.String()
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
request.SetFormData(formatBodyData)
|
||||||
|
return nil
|
||||||
|
}
|
21
httpclient/implement/request/write_json.go
Normal file
21
httpclient/implement/request/write_json.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Package request ...
|
||||||
|
//
|
||||||
|
// Description : request ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 2025-05-08 14:21
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"resty.dev/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WriteJson application/json写入
|
||||||
|
type WriteJson struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WriteJson) Write(request *resty.Request, bodyData map[string]any) error {
|
||||||
|
request.SetBody(bodyData)
|
||||||
|
return nil
|
||||||
|
}
|
46
httpclient/implement/request/write_xml.go
Normal file
46
httpclient/implement/request/write_xml.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Package request ...
|
||||||
|
//
|
||||||
|
// Description : request ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 2025-05-08 14:21
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||||
|
"resty.dev/v3"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/dynamic-struct/wrapper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WriteXml application/xml body写入
|
||||||
|
type WriteXml struct{}
|
||||||
|
|
||||||
|
func (w *WriteXml) Write(request *resty.Request, bodyData map[string]any) error {
|
||||||
|
if nil == bodyData {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
bodyBytes []byte
|
||||||
|
xmlBodyByte []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
if bodyBytes, err = serialize.JSON.MarshalForByte(bodyData); nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
instance, err := wrapper.NewJson(string(bodyBytes), &wrapper.Option{XmlName: "RequestBody"})
|
||||||
|
if nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if nil == instance {
|
||||||
|
return errors.New("xml generate instance is nil")
|
||||||
|
}
|
||||||
|
if xmlBodyByte, err = instance.Marshal("xml"); nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
request.SetBody(bytes.NewReader(xmlBodyByte))
|
||||||
|
return nil
|
||||||
|
}
|
@ -41,6 +41,7 @@ type RequestConfigGroupItem struct {
|
|||||||
CacheInstance abstract.ICache `json:"-"` // 数据缓存实例
|
CacheInstance abstract.ICache `json:"-"` // 数据缓存实例
|
||||||
RateLimiter abstract.RateLimiter `json:"-"` // 流控实例
|
RateLimiter abstract.RateLimiter `json:"-"` // 流控实例
|
||||||
ResponseParser abstract.IResponse `json:"-"` // 响应数据解析
|
ResponseParser abstract.IResponse `json:"-"` // 响应数据解析
|
||||||
|
RequestBodyWrite abstract.IRequestBodyWrite `json:"-"` // 请求Body数据写入的实现
|
||||||
Condition any `json:"condition"` // TODO: 请求条件, 特定条件下不执行当前请求
|
Condition any `json:"condition"` // TODO: 请求条件, 特定条件下不执行当前请求
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,8 @@ import (
|
|||||||
|
|
||||||
// RequestOption 请求一些选项
|
// RequestOption 请求一些选项
|
||||||
type RequestOption struct {
|
type RequestOption struct {
|
||||||
CacheInstance abstract.ICache `json:"-"` // 数据结果缓存实例
|
CacheInstance abstract.ICache `json:"-"` // 数据结果缓存实例
|
||||||
RateLimiter abstract.RateLimiter `json:"-"` // 流控实例
|
RateLimiter abstract.RateLimiter `json:"-"` // 流控实例
|
||||||
ResponseParser abstract.IResponse `json:"-"` // 返回结果解析, 不配置使用内置实现
|
RequestBodyWrite abstract.IRequestBodyWrite `json:"-"` // 将请求Body写入请求实例
|
||||||
|
ResponseParser abstract.IResponse `json:"-"` // 返回结果解析, 不配置使用内置实现
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,12 @@
|
|||||||
package httpclient
|
package httpclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.zhangdeman.cn/zhangdeman/consts"
|
"git.zhangdeman.cn/zhangdeman/consts"
|
||||||
"git.zhangdeman.cn/zhangdeman/network/httpclient/define"
|
"git.zhangdeman.cn/zhangdeman/network/httpclient/define"
|
||||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
requestBoodyWriter "git.zhangdeman.cn/zhangdeman/network/httpclient/implement/request"
|
||||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||||
"github.com/tidwall/gjson"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"resty.dev/v3"
|
"resty.dev/v3"
|
||||||
@ -75,11 +75,11 @@ func initRequestConfig(reqConfig *define.Request) {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 15:00 2024/5/31
|
// Date : 15:00 2024/5/31
|
||||||
func NewRestyClient(reqConfig *define.Request, reqOption *RequestOption) (*resty.Client, *resty.Request) {
|
func NewRestyClient(reqConfig *define.Request, reqOption *RequestOption) (*resty.Client, *resty.Request, error) {
|
||||||
client := resty.New()
|
client := resty.New()
|
||||||
request := client.R()
|
request := client.R()
|
||||||
if nil == reqConfig {
|
if nil == reqConfig {
|
||||||
return client, request
|
return nil, nil, errors.New("request config is nil")
|
||||||
}
|
}
|
||||||
// 限流处理, 增加限流中间件
|
// 限流处理, 增加限流中间件
|
||||||
client.AddRequestMiddleware(func(client *resty.Client, request *resty.Request) error {
|
client.AddRequestMiddleware(func(client *resty.Client, request *resty.Request) error {
|
||||||
@ -93,7 +93,7 @@ func NewRestyClient(reqConfig *define.Request, reqOption *RequestOption) (*resty
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
initRequestConfig(reqConfig) // 初始化 + 格式化配置
|
initRequestConfig(reqConfig) // 初始化 + 格式化配置
|
||||||
client.SetAllowMethodGetPayload(true) // 配置 GET 请求允许带 Body
|
client.SetAllowMethodGetPayload(true) // 配置 GET 请求允许带 Body
|
||||||
client.SetAllowMethodDeletePayload(true) // 配置 DELETE 请求允许带 Body
|
client.SetAllowMethodDeletePayload(true) // 配置 DELETE 请求允许带 Body
|
||||||
@ -130,35 +130,29 @@ func NewRestyClient(reqConfig *define.Request, reqOption *RequestOption) (*resty
|
|||||||
Value: wrapper.AnyDataType(cookieValue).ToString().Value(),
|
Value: wrapper.AnyDataType(cookieValue).ToString().Value(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
request.SetCookies(cookieList) // 设置cookie
|
request.SetCookies(cookieList) // 设置cookie
|
||||||
setRestyBody(reqConfig, request) // 设置请求Body
|
if err := setRestyBody(reqConfig, reqOption, request); nil != err {
|
||||||
return client, request
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return client, request, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setRestyBody 设置请求BODY TODO: 支持xml / yml等
|
// setRestyBody 设置请求BODY
|
||||||
//
|
//
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 17:18 2024/5/31
|
// Date : 17:18 2024/5/31
|
||||||
func setRestyBody(reqConfig *define.Request, request *resty.Request) {
|
func setRestyBody(reqConfig *define.Request, requestOption *RequestOption, request *resty.Request) error {
|
||||||
if nil == reqConfig.Body || len(reqConfig.Body) == 0 {
|
if nil == reqConfig.Body {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
if strings.Contains(strings.ToLower(reqConfig.ContentType), consts.MimeTypeJson) {
|
if nil != requestOption && nil != requestOption.RequestBodyWrite {
|
||||||
request.SetBody(reqConfig.Body)
|
// 外部传入的实现
|
||||||
return
|
requestOption.RequestBodyWrite.Write(request, reqConfig.Body)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if strings.Contains(strings.ToLower(reqConfig.ContentType), consts.MimeTypeXWWWFormUrlencoded) {
|
// 外部没传入, 使用内置实现, 内置默认实现支持: xml/json/form, 如需其他, 自行扩展
|
||||||
bodyStr := serialize.JSON.MarshalForStringIgnoreError(reqConfig.Body)
|
return requestBoodyWriter.WriteBody(reqConfig.ContentType, request, reqConfig.Body)
|
||||||
bodyData := map[string]string{}
|
|
||||||
jsonObj := gjson.Parse(bodyStr)
|
|
||||||
jsonObj.ForEach(func(key, value gjson.Result) bool {
|
|
||||||
bodyData[key.String()] = value.String()
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
request.SetFormData(bodyData)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// formatHeader 格式化header
|
// formatHeader 格式化header
|
||||||
|
Loading…
x
Reference in New Issue
Block a user