响应自适应解析 + 逻辑优化 #8

Merged
zhangdeman merged 9 commits from feature/auto_support_response_type into master 2025-05-07 17:39:50 +08:00
5 changed files with 56 additions and 7 deletions
Showing only changes of commit 1fe39e0547 - Show all commits

View File

@ -22,7 +22,7 @@ type IResponseParser interface {
// IResponse 响应解析
type IResponse interface {
// Parse 解析响应
Parse(reqConfig *define.Request, response *define.Response)
Parse(reqConfig *define.Request, response *define.Response) error
// BusinessSuccess 业务状态码是否成功
BusinessSuccess(reqCfg *define.Request, response *define.Response) bool
// HttpSuccess http状态码是否成功

View File

@ -8,21 +8,23 @@
package implement
import (
"errors"
"fmt"
"git.zhangdeman.cn/zhangdeman/consts"
"git.zhangdeman.cn/zhangdeman/network/httpclient/define"
"git.zhangdeman.cn/zhangdeman/serialize"
"github.com/tidwall/gjson"
"strings"
)
// Response 响应结果解析
type Response struct {
}
func (r *Response) Parse(reqConfig *define.Request, response *define.Response) {
func (r *Response) Parse(reqConfig *define.Request, response *define.Response) error {
r.fillResponseHeader(response)
r.fillResponseCookie(response)
r.fillResponseBody(reqConfig, response)
return
return r.fillResponseBody(reqConfig, response)
}
// fillResponseHeader 填充响应header
@ -60,8 +62,38 @@ func (r *Response) fillResponseCookie(response *define.Response) {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 21:38 2024/6/5
func (r *Response) fillResponseBody(reqCfg *define.Request, response *define.Response) {
response.Data = string(response.RestyResponse.Body())
func (r *Response) fillResponseBody(reqCfg *define.Request, response *define.Response) error {
// 解析响应数据类型
responseContentType := response.RestyResponse.Header().Get(consts.HeaderKeyContentType.String())
if responseContentType == "" {
// 返回数据未说明 Content-Type
return errors.New("response content type is empty")
}
typeArr := strings.Split(strings.Split(responseContentType, ";")[0], "/")
responseType := "json"
if len(typeArr) > 0 {
responseType = typeArr[len(typeArr)-1]
}
parser := ResponseParserTable[responseType]
if parser == nil {
// 未读取到的, 不支持解析对应的响应数据
return errors.New("response type " + responseType + " is not support")
}
var (
err error
res map[string]any
jsonByte []byte
)
if err = parser.Unmarshal(response.RestyResponse.Body(), &res); nil != err {
return errors.New("response parse body error :" + err.Error())
}
if jsonByte, err = parser.MarshalForByte(res); nil != err {
return errors.New("response body Marshal error :" + err.Error())
}
response.Data = string(jsonByte)
response.Code = gjson.Get(response.Data, reqCfg.CodeField).String()
response.Message = gjson.Get(response.Data, reqCfg.MessageField).String()
businessData := gjson.Get(response.Data, reqCfg.DataField)
@ -96,6 +128,7 @@ func (r *Response) fillResponseBody(reqCfg *define.Request, response *define.Res
response.ExtendData[key.String()] = value.String()
return true
})
return nil
}
// BusinessSuccess ...

View File

@ -13,6 +13,10 @@ import (
)
// ResponseParserTable 响应数据解析器
// 此处为内置解析实现, 未加锁, 未做并发安全处理
// 原因: 无论 Add 还是 Delete, 均应在服务初始化阶段调用, 而在服务完成初始化, 完全启动之后, 应该只有读操作
// 如果强要运行时, 动态操作此配置表, 需在外部调用处自行加锁
// 也可完全自行实现相关解析实例, 在请求时通过 RequestOption 传入, 则控制权完全贵开发者所有
var ResponseParserTable = map[string]abstract.IResponseParser{
"json": serialize.JSON,
"xml": serialize.Xml,
@ -21,3 +25,13 @@ var ResponseParserTable = map[string]abstract.IResponseParser{
"yaml": serialize.Yml,
"text": serialize.JSON,
}
// AddResponseParser 新增一个解析实现
func AddResponseParser(t string, parser abstract.IResponseParser) {
ResponseParserTable[t] = parser
}
// RemoveResponseParser 移除一个解析实现
func RemoveResponseParser(t string) {
delete(ResponseParserTable, t)
}

View File

@ -39,6 +39,7 @@ type RequestConfigGroupItem struct {
FailBehavior *RequestConfigGroupItemFailBehavior `json:"fail_behavior"` // 失败的行为, 不配置, 默认失败break
FinalFailureAllow bool `json:"final_failure_allow"` // 已经确定当前请求是最终失败了,当前请求是否允许执行
CacheInstance abstract.ICache `json:"-"` // 数据缓存实例
ResponseParser abstract.IResponse `json:"-"` // 响应数据解析
Condition any `json:"condition"` // TODO: 请求条件, 特定条件下不执行当前请求
}

View File

@ -148,7 +148,8 @@ func (c *client) doRequest(apiList []*RequestConfigGroupItem) bool {
apiCfg.RequestCfg.Cookie = param[strings.ToLower(consts.RequestDataLocationCookie.String())] // cookie
apiCfg.RequestCfg.Query = param[strings.ToLower(consts.RequestDataLocationQuery.String())] // query
if httpClient, err = httpclient.NewHttpClient(apiCfg.RequestCfg, &httpclient.RequestOption{
CacheInstance: apiCfg.CacheInstance,
CacheInstance: apiCfg.CacheInstance,
ResponseParser: apiCfg.ResponseParser,
}); nil != err {
// 此处获取客户端实例即发生异常, 忽略一切配置, 直接作为全局失败, 后续也不请求了
c.resp.ErrorCode = "-500"