优化http请求之后对响应结果的处理
1. http状态验证 2. 业务状态码验证 3. 业务数据提取 4. 异常处理统一使用exception库
This commit is contained in:
parent
4a00f91d87
commit
89e73cc9d9
1
go.mod
1
go.mod
@ -13,6 +13,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20230811030300-6f850372c88c // indirect
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20230811030300-6f850372c88c // indirect
|
||||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20230307094841-e437ba87af10 // indirect
|
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20230307094841-e437ba87af10 // indirect
|
||||||
|
git.zhangdeman.cn/zhangdeman/exception v0.0.0-20230819024237-f674702ad28d // indirect
|
||||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20230811032817-e6ad534a9a10 // indirect
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20230811032817-e6ad534a9a10 // indirect
|
||||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230811055014-2e36e7b1ac67 // indirect
|
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230811055014-2e36e7b1ac67 // indirect
|
||||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -2,6 +2,8 @@ git.zhangdeman.cn/zhangdeman/consts v0.0.0-20230811030300-6f850372c88c h1:Dan3iS
|
|||||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20230811030300-6f850372c88c/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20230811030300-6f850372c88c/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20230307094841-e437ba87af10 h1:+Lg4vXFEiWVKjhUJdXuoP0AgjGT49oqJ3301STnZErk=
|
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20230307094841-e437ba87af10 h1:+Lg4vXFEiWVKjhUJdXuoP0AgjGT49oqJ3301STnZErk=
|
||||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20230307094841-e437ba87af10/go.mod h1:+Lc0zYF8sylRi75A7NGmObrLxugwAZa8WVpWh2eh5X0=
|
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20230307094841-e437ba87af10/go.mod h1:+Lc0zYF8sylRi75A7NGmObrLxugwAZa8WVpWh2eh5X0=
|
||||||
|
git.zhangdeman.cn/zhangdeman/exception v0.0.0-20230819024237-f674702ad28d h1:XqjAykNMm/ai1+CebqcxBKXmIQqZNyYmTeIufLTXQJc=
|
||||||
|
git.zhangdeman.cn/zhangdeman/exception v0.0.0-20230819024237-f674702ad28d/go.mod h1:Voc8J4ordx7nuMWpgACXXZULQy7ZIuBzcEIoS8VnDIw=
|
||||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20230811032817-e6ad534a9a10 h1:orhcMAKrcOajsBJCgssnb9O8YcLsPJvWuXF511gs5dc=
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20230811032817-e6ad534a9a10 h1:orhcMAKrcOajsBJCgssnb9O8YcLsPJvWuXF511gs5dc=
|
||||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20230811032817-e6ad534a9a10/go.mod h1:CzX5/WwGDTnKmewarnjkK5XcSRbgszTQTdTL3OUc/s4=
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20230811032817-e6ad534a9a10/go.mod h1:CzX5/WwGDTnKmewarnjkK5XcSRbgszTQTdTL3OUc/s4=
|
||||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230811055014-2e36e7b1ac67 h1:risi3/+SuH+snq/+/1dvqDrNyiclCi5weHMixg7IgO8=
|
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230811055014-2e36e7b1ac67 h1:risi3/+SuH+snq/+/1dvqDrNyiclCi5weHMixg7IgO8=
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
package httpclient
|
package httpclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
"git.zhangdeman.cn/zhangdeman/exception"
|
||||||
"github.com/ddliu/go-httpclient"
|
"github.com/ddliu/go-httpclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -41,6 +41,21 @@ const (
|
|||||||
DefaultConnectTimeout = 1000
|
DefaultConnectTimeout = 1000
|
||||||
// DefaultReadTimeout 默认读取超时时间, 毫秒
|
// DefaultReadTimeout 默认读取超时时间, 毫秒
|
||||||
DefaultReadTimeout = 1000
|
DefaultReadTimeout = 1000
|
||||||
|
// DefaultResponseCodeField 默认code字段
|
||||||
|
DefaultResponseCodeField = "code"
|
||||||
|
// DefaultResponseMessageField 默认message字段
|
||||||
|
DefaultResponseMessageField = "message"
|
||||||
|
// DefaultResponseDataField 默认数据字段
|
||||||
|
DefaultResponseDataField = "data"
|
||||||
|
// DefaultMessage 接口响应失败
|
||||||
|
DefaultMessage = "api request fail"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultSuccessCode 默认成功状态码
|
||||||
|
DefaultSuccessCode = []string{"0", "200"}
|
||||||
|
// DefaultSuccessHttpCode 默认成功http状态码
|
||||||
|
DefaultSuccessHttpCode = []string{"200"}
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -99,10 +114,10 @@ type Timeout struct {
|
|||||||
type ApiResponse struct {
|
type ApiResponse struct {
|
||||||
RequestConfig *ApiRequestConfig `json:"request_config"` // 请求配置
|
RequestConfig *ApiRequestConfig `json:"request_config"` // 请求配置
|
||||||
Response *httpclient.Response `json:"response"` // 响应体
|
Response *httpclient.Response `json:"response"` // 响应体
|
||||||
Exception *Exception `json:"exception"` // 异常信息
|
Exception exception.IException `json:"-"` // 异常信息
|
||||||
StartRequestTime int64 `json:"start_request_time"` // 开始请求时间, 纳秒
|
StartRequestTime int64 `json:"start_request_time"` // 开始请求时间, 纳秒
|
||||||
FinishRequestTime int64 `json:"finish_request_time"` // 完成请求时间,纳秒
|
FinishRequestTime int64 `json:"finish_request_time"` // 完成请求时间,纳秒
|
||||||
Code string `json:"code"` // 业务状态码
|
Code string `json:"code"` // 业务状态码
|
||||||
Message string `json:"message"` // 状态码描述
|
Message string `json:"message"` // 状态码描述
|
||||||
Data wrapper.String `json:"data"` // 响应数据
|
Data string `json:"data"` // 响应数据
|
||||||
}
|
}
|
||||||
|
@ -11,68 +11,17 @@
|
|||||||
// Date: 2022/05/01 20:40:08
|
// Date: 2022/05/01 20:40:08
|
||||||
package httpclient
|
package httpclient
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// Exception 定义异常
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Description: 对于各种异常的描述
|
|
||||||
//
|
|
||||||
// Date: 2022/05/01 20:48:21
|
|
||||||
type Exception struct {
|
|
||||||
Code string `json:"code"` // 异常的标识码
|
|
||||||
Message string `json:"message"` // 异常的描述
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// BindRouterParamNotFound 绑定到路由的参数不存在
|
|
||||||
BindRouterParamNotFound = "404001"
|
|
||||||
// ResponseCodeNotFound 响应结果获取不到状态码字段
|
// ResponseCodeNotFound 响应结果获取不到状态码字段
|
||||||
ResponseCodeNotFound = "404002"
|
ResponseCodeNotFound = 404000000002
|
||||||
// ResponseMessageNotFound 响应结果获取不到状态码描述字段
|
|
||||||
ResponseMessageNotFound = "404003"
|
|
||||||
// ResponseDataNotFound 响应结果获取不到数据字段
|
// ResponseDataNotFound 响应结果获取不到数据字段
|
||||||
ResponseDataNotFound = "404004"
|
ResponseDataNotFound = 404000000004
|
||||||
// DomainInvalid 域名设置错误, 必须是 http:// 或者 https:// 开头
|
|
||||||
DomainInvalid = "400001"
|
|
||||||
// SendRequestError 请求发送出现异常
|
// SendRequestError 请求发送出现异常
|
||||||
SendRequestError = "400002"
|
SendRequestError = 400000000002
|
||||||
// ReadResponseBodyError 读取响应数据体出现异常
|
// ReadResponseBodyError 读取响应数据体出现异常
|
||||||
ReadResponseBodyError = "400003"
|
ReadResponseBodyError = 400000000003
|
||||||
// RequestMethodNotSupport 请求方法不支持
|
// RequestMethodNotSupport 请求方法不支持
|
||||||
RequestMethodNotSupport = "405001"
|
RequestMethodNotSupport = 405000000001
|
||||||
|
// ResponseHttpCodeIsNotSuccess 响应的http状态码非成功
|
||||||
|
ResponseHttpCodeIsNotSuccess = 500000000001
|
||||||
)
|
)
|
||||||
|
|
||||||
// exceptionTable ...
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Description: 异常信息表
|
|
||||||
//
|
|
||||||
// Date: 2022/05/01 21:02:55
|
|
||||||
var exceptionTable = map[string]string{
|
|
||||||
BindRouterParamNotFound: "绑定到路由的参数{{bind_router_param}}不存在, 请确认参数配置",
|
|
||||||
ResponseCodeNotFound: "基于配置无法获取响应体状态码, 请检查 response_code_field 的配置, 当前配置 {response_code_field}",
|
|
||||||
ResponseMessageNotFound: "基于配置无法获取响应体状态码, 请检查 response_code_message 的配置, 当前配置 {response_code_message}",
|
|
||||||
ResponseDataNotFound: "基于配置无法获取响应体状态码, 请检查 {response_code_data} 的配置, 当前配置 {response_code_data}",
|
|
||||||
DomainInvalid: "api域名配置非法, 必须以 http:// 或者 https:// 开头, 当前配置 {domain}",
|
|
||||||
RequestMethodNotSupport: "当前请求方法 {method} 不支持, 请核对相关配置",
|
|
||||||
SendRequestError: "请求发送出现异常, 异常原因 : {real_reason}",
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewException 实力化异常
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 2022/05/01 21:02:07
|
|
||||||
func NewException(code string, exceptionData map[string]string) *Exception {
|
|
||||||
mes := exceptionTable[code]
|
|
||||||
for k, v := range exceptionData {
|
|
||||||
mes = strings.ReplaceAll(mes, "{"+k+"}", v)
|
|
||||||
}
|
|
||||||
return &Exception{
|
|
||||||
Code: code,
|
|
||||||
Message: mes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -20,9 +20,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tidwall/gjson"
|
"git.zhangdeman.cn/zhangdeman/exception"
|
||||||
|
|
||||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
"github.com/tidwall/gjson"
|
||||||
|
|
||||||
"github.com/ddliu/go-httpclient"
|
"github.com/ddliu/go-httpclient"
|
||||||
)
|
)
|
||||||
@ -54,7 +54,7 @@ func Request(apiConfig *ApiRequestConfig, header map[string]string, param map[st
|
|||||||
default:
|
default:
|
||||||
return &ApiResponse{
|
return &ApiResponse{
|
||||||
RequestConfig: apiConfig,
|
RequestConfig: apiConfig,
|
||||||
Exception: NewException(RequestMethodNotSupport, map[string]string{"method": apiConfig.Method}),
|
Exception: exception.New(RequestMethodNotSupport, 0, map[string]string{"method": apiConfig.Method}, apiConfig.Method+" : request method is not support"),
|
||||||
Response: nil,
|
Response: nil,
|
||||||
StartRequestTime: time.Now().UnixNano(),
|
StartRequestTime: time.Now().UnixNano(),
|
||||||
FinishRequestTime: time.Now().UnixNano(),
|
FinishRequestTime: time.Now().UnixNano(),
|
||||||
@ -228,9 +228,26 @@ func send(apiConfig *ApiRequestConfig, header map[string]string) *ApiResponse {
|
|||||||
responseByte []byte
|
responseByte []byte
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 填充默认配置
|
||||||
if len(apiConfig.ResponseCodeFieldLocation) == 0 {
|
if len(apiConfig.ResponseCodeFieldLocation) == 0 {
|
||||||
apiConfig.ResponseCodeFieldLocation = ResponseCodeFieldLocationDefault
|
apiConfig.ResponseCodeFieldLocation = ResponseCodeFieldLocationDefault
|
||||||
}
|
}
|
||||||
|
if len(apiConfig.ResponseCodeField) == 0 {
|
||||||
|
apiConfig.ResponseCodeField = DefaultResponseCodeField
|
||||||
|
}
|
||||||
|
if len(apiConfig.ResponseMessageField) == 0 {
|
||||||
|
apiConfig.ResponseMessageField = DefaultResponseMessageField
|
||||||
|
}
|
||||||
|
if len(apiConfig.ResponseDataField) == 0 {
|
||||||
|
apiConfig.ResponseDataField = DefaultResponseDataField
|
||||||
|
}
|
||||||
|
if len(apiConfig.SuccessCodeList) == 0 {
|
||||||
|
apiConfig.SuccessCodeList = DefaultSuccessCode
|
||||||
|
}
|
||||||
|
if len(apiConfig.SuccessHttpCodeList) == 0 {
|
||||||
|
apiConfig.SuccessHttpCodeList = DefaultSuccessHttpCode
|
||||||
|
}
|
||||||
|
|
||||||
response := &ApiResponse{
|
response := &ApiResponse{
|
||||||
RequestConfig: apiConfig,
|
RequestConfig: apiConfig,
|
||||||
Response: nil,
|
Response: nil,
|
||||||
@ -239,7 +256,7 @@ func send(apiConfig *ApiRequestConfig, header map[string]string) *ApiResponse {
|
|||||||
FinishRequestTime: 0,
|
FinishRequestTime: 0,
|
||||||
Code: "",
|
Code: "",
|
||||||
Message: "",
|
Message: "",
|
||||||
Data: wrapper.String("{}"),
|
Data: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -248,26 +265,76 @@ func send(apiConfig *ApiRequestConfig, header map[string]string) *ApiResponse {
|
|||||||
|
|
||||||
client = getHttpClient(apiConfig, header)
|
client = getHttpClient(apiConfig, header)
|
||||||
if response.Response, err = client.Do(apiConfig.Method, apiConfig.FullURL, nil, bytes.NewReader(apiConfig.Body)); nil != err {
|
if response.Response, err = client.Do(apiConfig.Method, apiConfig.FullURL, nil, bytes.NewReader(apiConfig.Body)); nil != err {
|
||||||
response.Exception = NewException(SendRequestError, map[string]string{"real_reason": err.Error()})
|
response.Exception = exception.New(SendRequestError, 0, map[string]string{"real_reason": err.Error()}, "http request send fail : "+err.Error())
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
if responseByte, err = io.ReadAll(response.Response.Body); nil != err {
|
if responseByte, err = io.ReadAll(response.Response.Body); nil != err {
|
||||||
response.Exception = NewException(ReadResponseBodyError, map[string]string{"real_reason": err.Error()})
|
response.Exception = exception.New(ReadResponseBodyError, response.Response.StatusCode, map[string]string{"real_reason": err.Error()}, "response body read fail : "+err.Error())
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
// 提取响应数据
|
// 判断http状态码是否为成功
|
||||||
if response.RequestConfig.ResponseDataField == ResponseBodyAsData {
|
isHttpSuccess := false
|
||||||
response.Data = wrapper.String(string(responseByte))
|
responseHttpCode := fmt.Sprintf("%v", response.Response.StatusCode)
|
||||||
} else {
|
for _, itemSuccessHttpCode := range response.RequestConfig.SuccessHttpCodeList {
|
||||||
response.Data = wrapper.String(gjson.GetBytes(responseByte, response.RequestConfig.ResponseDataField).String())
|
if responseHttpCode == itemSuccessHttpCode {
|
||||||
|
isHttpSuccess = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// http请求失败
|
||||||
|
if !isHttpSuccess {
|
||||||
|
response.Exception = exception.New(ResponseHttpCodeIsNotSuccess, response.Response.StatusCode, map[string]string{
|
||||||
|
"real_reason": responseHttpCode + " : response http code is not success",
|
||||||
|
}, responseHttpCode+" : response http code is not success")
|
||||||
|
return response
|
||||||
}
|
}
|
||||||
// 提取响应错误码
|
// 提取响应错误码
|
||||||
if response.RequestConfig.ResponseCodeFieldLocation == ResponseCodeFieldLocationHeader {
|
if response.RequestConfig.ResponseCodeFieldLocation == ResponseCodeFieldLocationHeader {
|
||||||
response.Code = response.Response.Header.Get(response.RequestConfig.ResponseCodeField)
|
response.Code = response.Response.Header.Get(response.RequestConfig.ResponseCodeField)
|
||||||
} else {
|
} else {
|
||||||
response.Code = gjson.GetBytes(responseByte, response.RequestConfig.ResponseCodeField).String()
|
businessCode := gjson.GetBytes(responseByte, response.RequestConfig.ResponseCodeField)
|
||||||
|
if businessCode.Exists() {
|
||||||
|
response.Code = businessCode.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否提取到响应状态码
|
||||||
|
if len(response.Code) == 0 {
|
||||||
|
response.Exception = exception.New(ResponseCodeNotFound, response.Response.StatusCode, map[string]string{
|
||||||
|
"real_reason": "parse response business code fail",
|
||||||
|
}, fmt.Sprintf("business code location : %v, business code name : %v, parse business code fail", response.RequestConfig.ResponseCodeFieldLocation, response.RequestConfig.ResponseCodeField))
|
||||||
}
|
}
|
||||||
// 提取响应文案
|
// 提取响应文案
|
||||||
response.Message = gjson.GetBytes(responseByte, response.RequestConfig.ResponseMessageField).String()
|
response.Message = gjson.GetBytes(responseByte, response.RequestConfig.ResponseMessageField).String()
|
||||||
|
if len(response.Message) == 0 {
|
||||||
|
response.Message = DefaultMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断响应状态码是否成功
|
||||||
|
isBusinessCodeSuccess := false
|
||||||
|
for _, itemSuccessCode := range response.RequestConfig.SuccessHttpCodeList {
|
||||||
|
if itemSuccessCode == response.Code {
|
||||||
|
isBusinessCodeSuccess = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isBusinessCodeSuccess {
|
||||||
|
response.Exception = exception.New(ResponseCodeNotFound, response.Response.StatusCode, map[string]string{}, response.Message)
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取响应数据
|
||||||
|
if response.RequestConfig.ResponseDataField == ResponseBodyAsData {
|
||||||
|
response.Data = string(responseByte)
|
||||||
|
} else {
|
||||||
|
responseData := gjson.GetBytes(responseByte, response.RequestConfig.ResponseDataField)
|
||||||
|
if !responseData.Exists() {
|
||||||
|
response.Exception = exception.New(ResponseDataNotFound, response.Response.StatusCode, map[string]string{}, "response data not found, data field name : "+response.RequestConfig.ResponseDataField)
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
response.Data = responseData.String()
|
||||||
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user