优化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 (
|
||||
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/exception v0.0.0-20230819024237-f674702ad28d // indirect
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20230811032817-e6ad534a9a10 // indirect
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230811055014-2e36e7b1ac67 // 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/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/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/go.mod h1:CzX5/WwGDTnKmewarnjkK5XcSRbgszTQTdTL3OUc/s4=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230811055014-2e36e7b1ac67 h1:risi3/+SuH+snq/+/1dvqDrNyiclCi5weHMixg7IgO8=
|
||||
|
@ -12,7 +12,7 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
"git.zhangdeman.cn/zhangdeman/exception"
|
||||
"github.com/ddliu/go-httpclient"
|
||||
)
|
||||
|
||||
@ -41,6 +41,21 @@ const (
|
||||
DefaultConnectTimeout = 1000
|
||||
// DefaultReadTimeout 默认读取超时时间, 毫秒
|
||||
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 (
|
||||
@ -99,10 +114,10 @@ type Timeout struct {
|
||||
type ApiResponse struct {
|
||||
RequestConfig *ApiRequestConfig `json:"request_config"` // 请求配置
|
||||
Response *httpclient.Response `json:"response"` // 响应体
|
||||
Exception *Exception `json:"exception"` // 异常信息
|
||||
Exception exception.IException `json:"-"` // 异常信息
|
||||
StartRequestTime int64 `json:"start_request_time"` // 开始请求时间, 纳秒
|
||||
FinishRequestTime int64 `json:"finish_request_time"` // 完成请求时间,纳秒
|
||||
Code string `json:"code"` // 业务状态码
|
||||
Message string `json:"message"` // 状态码描述
|
||||
Data wrapper.String `json:"data"` // 响应数据
|
||||
Data string `json:"data"` // 响应数据
|
||||
}
|
||||
|
@ -11,68 +11,17 @@
|
||||
// Date: 2022/05/01 20:40:08
|
||||
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 (
|
||||
// BindRouterParamNotFound 绑定到路由的参数不存在
|
||||
BindRouterParamNotFound = "404001"
|
||||
// ResponseCodeNotFound 响应结果获取不到状态码字段
|
||||
ResponseCodeNotFound = "404002"
|
||||
// ResponseMessageNotFound 响应结果获取不到状态码描述字段
|
||||
ResponseMessageNotFound = "404003"
|
||||
ResponseCodeNotFound = 404000000002
|
||||
// ResponseDataNotFound 响应结果获取不到数据字段
|
||||
ResponseDataNotFound = "404004"
|
||||
// DomainInvalid 域名设置错误, 必须是 http:// 或者 https:// 开头
|
||||
DomainInvalid = "400001"
|
||||
ResponseDataNotFound = 404000000004
|
||||
// SendRequestError 请求发送出现异常
|
||||
SendRequestError = "400002"
|
||||
SendRequestError = 400000000002
|
||||
// ReadResponseBodyError 读取响应数据体出现异常
|
||||
ReadResponseBodyError = "400003"
|
||||
ReadResponseBodyError = 400000000003
|
||||
// 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"
|
||||
"time"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"git.zhangdeman.cn/zhangdeman/exception"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/ddliu/go-httpclient"
|
||||
)
|
||||
@ -54,7 +54,7 @@ func Request(apiConfig *ApiRequestConfig, header map[string]string, param map[st
|
||||
default:
|
||||
return &ApiResponse{
|
||||
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,
|
||||
StartRequestTime: time.Now().UnixNano(),
|
||||
FinishRequestTime: time.Now().UnixNano(),
|
||||
@ -228,9 +228,26 @@ func send(apiConfig *ApiRequestConfig, header map[string]string) *ApiResponse {
|
||||
responseByte []byte
|
||||
)
|
||||
|
||||
// 填充默认配置
|
||||
if len(apiConfig.ResponseCodeFieldLocation) == 0 {
|
||||
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{
|
||||
RequestConfig: apiConfig,
|
||||
Response: nil,
|
||||
@ -239,7 +256,7 @@ func send(apiConfig *ApiRequestConfig, header map[string]string) *ApiResponse {
|
||||
FinishRequestTime: 0,
|
||||
Code: "",
|
||||
Message: "",
|
||||
Data: wrapper.String("{}"),
|
||||
Data: "",
|
||||
}
|
||||
|
||||
defer func() {
|
||||
@ -248,26 +265,76 @@ func send(apiConfig *ApiRequestConfig, header map[string]string) *ApiResponse {
|
||||
|
||||
client = getHttpClient(apiConfig, header)
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
// 提取响应数据
|
||||
if response.RequestConfig.ResponseDataField == ResponseBodyAsData {
|
||||
response.Data = wrapper.String(string(responseByte))
|
||||
} else {
|
||||
response.Data = wrapper.String(gjson.GetBytes(responseByte, response.RequestConfig.ResponseDataField).String())
|
||||
// 判断http状态码是否为成功
|
||||
isHttpSuccess := false
|
||||
responseHttpCode := fmt.Sprintf("%v", response.Response.StatusCode)
|
||||
for _, itemSuccessHttpCode := range response.RequestConfig.SuccessHttpCodeList {
|
||||
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 {
|
||||
response.Code = response.Response.Header.Get(response.RequestConfig.ResponseCodeField)
|
||||
} 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()
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user