Merge pull request 'feat: 升级HTTP请求, 支持自定义message location 和 解析整个响应body' (#12) from feature/upgrade_response_parse into master

Reviewed-on: #12
This commit is contained in:
2025-12-13 22:38:02 +08:00
2 changed files with 45 additions and 28 deletions

View File

@ -9,6 +9,7 @@ package define
import ( import (
"context" "context"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -18,27 +19,28 @@ import (
// //
// Date : 17:10 2024/5/24 // Date : 17:10 2024/5/24
type Request struct { type Request struct {
Ctx context.Context `json:"-"` // 请求上下文 Ctx context.Context `json:"-"` // 请求上下文
PathParam map[string]string `json:"path_param"` // 替换url中的占位符 PathParam map[string]string `json:"path_param"` // 替换url中的占位符
Body map[string]any `json:"body"` // 请求Body Body map[string]any `json:"body"` // 请求Body
Header map[string]any `json:"header"` // 请求Header Header map[string]any `json:"header"` // 请求Header
Cookie map[string]any `json:"cookie"` // 请求Cookie Cookie map[string]any `json:"cookie"` // 请求Cookie
Query map[string]any `json:"query"` // 请求query Query map[string]any `json:"query"` // 请求query
Static map[string]map[string]any `json:"static"` // 静态参数: location => valName => val 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"` // 请求类型 ContentType string `json:"content_type"` // 请求类型
Method string `json:"method"` // 请求方法 Method string `json:"method"` // 请求方法
DataField string `json:"data_field"` // 数据字段 DataField string `json:"data_field"` // 数据字段,// 数据字段 BODY_ROOT 代表整个BODY 都是带解析数据
CodeField string `json:"code_field"` // 业务状态码字段 CodeField string `json:"code_field"` // 业务状态码字段
CodeLocation string `json:"code_location"` // 业务状态码位置 CodeLocation string `json:"code_location"` // 业务状态码位置
MessageField string `json:"message_field"` // code描述字段 MessageField string `json:"message_field"` // code描述字段
DataReceiver any `json:"-"` // 响应data部分数据解析 MessageFieldLocation string `json:"message_field_location"` // code 描述字段位置
SuccessHttpCodeList []int `json:"success_http_code_list"` // 哪些http状态码视为成功, 不配置, 默认2xx DataReceiver any `json:"-"` // 响应data部分数据解析
SuccessCodeList []string `json:"success_code_list"` // 哪些业务状态码视为成功 SuccessHttpCodeList []int `json:"success_http_code_list"` // 哪些http状态码视为成功, 不配置, 默认2xx
ConnectTimeout int64 `json:"connect_timeout"` // 连接超时时间: ms SuccessCodeList []string `json:"success_code_list"` // 哪些业务状态码视为成功
ReadTimeout int64 `json:"read_timeout"` // 读取超时时间 ConnectTimeout int64 `json:"connect_timeout"` // 连接超时时间: ms
RetryRule *RequestRetryRule `json:"retry_rule"` // 重试规则 ReadTimeout int64 `json:"read_timeout"` // 读取超时时间
Logger *zap.Logger `json:"-"` // 日志记录器 RetryRule *RequestRetryRule `json:"retry_rule"` // 重试规则
Logger *zap.Logger `json:"-"` // 日志记录器
} }
// RequestRetryRule 重试规则 // RequestRetryRule 重试规则

View File

@ -10,12 +10,13 @@ package implement
import ( import (
"errors" "errors"
"fmt" "fmt"
"net/http"
"strings"
"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" "git.zhangdeman.cn/zhangdeman/serialize"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
"net/http"
"strings"
) )
// Response 响应结果解析 // Response 响应结果解析
@ -98,21 +99,35 @@ func (r *Response) fillResponseBody(reqCfg *define.Request, response *define.Res
return errors.New("response body Marshal error :" + err.Error()) return errors.New("response body Marshal error :" + err.Error())
} }
response.Data = string(jsonByte) response.Data = string(jsonByte)
if strings.ToLower(reqCfg.CodeLocation) == "header" { if strings.ToUpper(reqCfg.CodeLocation) == consts.ResponseDataLocationHeader.String() {
if reqCfg.CodeField == "code" { if reqCfg.CodeField == "" || reqCfg.CodeField == "code" {
response.Code = fmt.Sprintf("%v", response.HttpCode) response.Code = fmt.Sprintf("%v", response.HttpCode)
response.Message = response.RestyResponse.Status()
} else { } else {
response.Code = response.RestyResponse.Header().Get(reqCfg.CodeField) response.Code = response.RestyResponse.Header().Get(reqCfg.CodeField)
response.Message = response.RestyResponse.Header().Get(reqCfg.MessageField)
} }
} else { } else {
// 统一认为Body // 统一认为Body
response.Code = gjson.Get(response.Data, reqCfg.CodeField).String() response.Code = gjson.Get(response.Data, reqCfg.CodeField).String()
}
if reqCfg.MessageFieldLocation == "" {
reqCfg.MessageFieldLocation = reqCfg.CodeLocation
}
if strings.ToUpper(reqCfg.MessageFieldLocation) == consts.ResponseDataLocationBody.String() {
// header, 统一使用 http status
response.Message = response.RestyResponse.Status()
} else {
response.Message = gjson.Get(response.Data, reqCfg.MessageField).String() response.Message = gjson.Get(response.Data, reqCfg.MessageField).String()
} }
businessData := gjson.Get(response.Data, reqCfg.DataField) var businessData gjson.Result
if reqCfg.DataField == "" || reqCfg.DataField == consts.ResponseDataLocationBodyRoot.String() {
// 整个Body都是数据
businessData = gjson.Parse(response.Data)
} else {
businessData = gjson.Get(response.Data, reqCfg.DataField)
}
if businessData.Value() == nil { if businessData.Value() == nil {
// data为空指针, 归一化成空对象 // data为空指针, 归一化成空对象
response.Body = map[string]any{} response.Body = map[string]any{}