调整AccessPlatformAPIWithRetry中的调试输出信息

+wxpayapi.CloseOrder
This commit is contained in:
gazebo
2019-12-20 09:46:27 +08:00
parent d95a14d314
commit 1c4ae2582e
4 changed files with 111 additions and 51 deletions

View File

@@ -116,9 +116,9 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http.
request.Header.Del(KeyTrackInfo)
}
trackInfo += ", " + utils.GetUUID()
baseapi.SugarLogger.Debugf("begin AccessPlatformAPIWithRetry:%s do:%s url:%v", trackInfo, request.Method, request.URL)
baseapi.SugarLogger.Debugf("begin AccessPlatformAPIWithRetry:%s do:%s url:%v, request:%s", trackInfo, request.Method, request.URL, getClonedData(request.URL, savedBuf))
response, err := client.Do(request)
baseapi.SugarLogger.Debugf("end AccessPlatformAPIWithRetry:%s do url:%v, request:%s", trackInfo, request.URL, getClonedData(request.URL, savedBuf))
baseapi.SugarLogger.Debugf("end AccessPlatformAPIWithRetry:%s do:%s url:%v", trackInfo, request.Method, request.URL)
if err != nil {
baseapi.SugarLogger.Debugf("AccessPlatformAPIWithRetry:%s client.Get return err:%v", trackInfo, err)
err, ok := err.(net.Error)
@@ -126,13 +126,13 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http.
if ok /*&& err.Timeout()*/ && recoverableErrorRetryCount <= config.MaxRecoverableRetryCount { // 只要是网络错误都重试
continue
} else {
baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry:%s access api url:%v, request:%v, error:%v", trackInfo, request.URL, getClonedData(request.URL, savedBuf), err)
baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry:%s access api url:%v, error:%v", trackInfo, request.URL, err)
return ErrAPIAccessFailed
}
}
usedMilliSecond := time.Now().Sub(beginTime) / time.Millisecond
if usedMilliSecond > 5000 {
baseapi.SugarLogger.Infof("AccessPlatformAPIWithRetry:%s access api too slow, url:%v, request:%v, usedMilliSecond:%d", trackInfo, request.URL, getClonedData(request.URL, savedBuf), usedMilliSecond)
baseapi.SugarLogger.Infof("AccessPlatformAPIWithRetry:%s access api too slow, url:%v, usedMilliSecond:%d", trackInfo, request.URL, usedMilliSecond)
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
@@ -144,9 +144,9 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http.
}
}
if bodyData, err := ioutil.ReadAll(response.Body); err == nil {
baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry:%s HTTP code is:%d, url:%v, request:%v, response:%s", trackInfo, response.StatusCode, request.URL, getClonedData(request.URL, savedBuf), string(bodyData))
baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry:%s HTTP code is:%d, url:%v, response:%s", trackInfo, response.StatusCode, request.URL, string(bodyData))
} else {
baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry:%s ioutil.ReadAll failed, HTTP code is:%d, url:%v, request:%v, error:%v", trackInfo, response.StatusCode, request.URL, getClonedData(request.URL, savedBuf), err)
baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry:%s ioutil.ReadAll failed, HTTP code is:%d, url:%v, error:%v", trackInfo, response.StatusCode, request.URL, err)
}
return ErrHTTPCodeIsNot200
}
@@ -158,14 +158,13 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http.
)
bodyData, err := ioutil.ReadAll(response.Body)
if err != nil {
baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry:%s ioutil.ReadAll failed, url:%v, request:%v, error:%v", trackInfo, request.URL, getClonedData(request.URL, savedBuf), err)
baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry:%s ioutil.ReadAll failed, url:%v, error:%v", trackInfo, request.URL, err)
errLevel = ErrLevelRecoverableErr // 读取数据错误,或数据格式错误认为是偶发情况,重试
} else {
baseapi.SugarLogger.Debugf("AccessPlatformAPIWithRetry:%s url:%v, response:%s", trackInfo, request.URL, string(bodyData))
if err = utils.TryUnmarshalUseNumber(bodyData, &bodyGeneral); err != nil {
parseJSONErr = err
err = nil // 尝试忽略解析成json错
} else {
baseapi.SugarLogger.Debugf("AccessPlatformAPIWithRetry:%s url:%v, response:%s", trackInfo, request.URL, utils.Format4Output(bodyGeneral, true))
}
// 临时处理返回值居然不是map的情况
if bodyMap2, ok := bodyGeneral.(map[string]interface{}); ok {
@@ -179,14 +178,14 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http.
}
}
errLevel, err = handleResponse(response, string(bodyData), bodyMap)
if err != nil && parseJSONErr != nil {
if err != nil && errLevel == ErrLevelRecoverableErr && parseJSONErr != nil {
const maxOutputLen = 2000
bodyDataLen := len(bodyData)
bodyData2 := bodyData
if bodyDataLen > maxOutputLen {
bodyData2 = bodyData2[:maxOutputLen]
}
baseapi.SugarLogger.Infof("AccessPlatformAPIWithRetry:%s TryUnmarshalUseNumber failed, url:%v, request:%v, error:%v, bodyData:%s", trackInfo, request.URL, getClonedData(request.URL, savedBuf), parseJSONErr, string(bodyData2))
baseapi.SugarLogger.Infof("AccessPlatformAPIWithRetry:%s TryUnmarshalUseNumber failed, url:%v, error:%v", trackInfo, request.URL, parseJSONErr)
}
}
@@ -208,7 +207,7 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http.
continue
}
}
baseapi.SugarLogger.Infof("AccessPlatformAPIWithRetry:%s failed, url:%v, response:%s, error:%v", trackInfo, request.URL, utils.Format4Output(bodyMap, true), err)
baseapi.SugarLogger.Infof("AccessPlatformAPIWithRetry:%s failed, url:%v, error:%v", trackInfo, request.URL, err)
return err
}
}

View File

@@ -37,6 +37,16 @@ type CallbackResponse struct {
type BaseResultMsg struct {
ReturnCode string `json:"return_code" xml:"return_code"`
ReturnMsg string `json:"return_msg" xml:"return_msg"`
AppID string `json:"appid" xml:"appid"`
DeviceInfo string `json:"device_info,omitempty" xml:"device_info,omitempty"`
MchID string `json:"mch_id" xml:"mch_id"`
NonceStr string `json:"nonce_str" xml:"nonce_str"`
Sign string `json:"sign" xml:"sign"`
ResultCode string `json:"result_code" xml:"result_code"`
ResultMsg string `json:"result_msg" xml:"result_msg"`
ErrCode string `json:"err_code,omitempty" xml:"err_code,omitempty"`
ErrCodeDes string `json:"err_code_des,omitempty" xml:"err_code_des,omitempty"`
}
type PayResultMsg struct {
@@ -49,6 +59,7 @@ type PayResultMsg struct {
NonceStr string `json:"nonce_str" xml:"nonce_str"`
Sign string `json:"sign" xml:"sign"`
ResultCode string `json:"result_code" xml:"result_code"`
ResultMsg string `json:"result_msg" xml:"result_msg"`
ErrCode string `json:"err_code,omitempty" xml:"err_code,omitempty"`
ErrCodeDes string `json:"err_code_des,omitempty" xml:"err_code_des,omitempty"`
@@ -90,6 +101,7 @@ type RefundResultMsg struct {
NonceStr string `json:"nonce_str" xml:"nonce_str"`
Sign string `json:"sign" xml:"sign"`
ResultCode string `json:"result_code" xml:"result_code"`
ResultMsg string `json:"result_msg" xml:"result_msg"`
ErrCode string `json:"err_code,omitempty" xml:"err_code,omitempty"`
ErrCodeDes string `json:"err_code_des,omitempty" xml:"err_code_des,omitempty"`
@@ -147,49 +159,47 @@ func (a *API) GetCallbackMsg(request *http.Request) (msg *CallbackMsg, callbackR
}
func (a *API) getCallbackMsg(msgBody string) (msg *CallbackMsg, callbackResponse *CallbackResponse) {
mapData, _, err := a.checkResultAsMap(msgBody)
mapData, _, err := a.parseXmlStrAsMap(msgBody)
if err != nil {
return nil, Err2CallbackResponse(err, "")
}
returnCode := utils.Interface2String(mapData["return_code"])
if returnCode != ResponseCodeSuccess { // 如果return_code出错直接返回
return nil, SuccessResponse
}
reqInfo := utils.Interface2String(mapData["req_info"])
transactionID := utils.Interface2String(mapData["transaction_id"])
if reqInfo == "" && transactionID != "" { // 对于支付结果通知进行签名验证(退款结果通知不支持验证)
sign := utils.Interface2String(mapData[sigKey])
desiredSign := a.signParam(mapData)
if desiredSign != sign {
return nil, Err2CallbackResponse(fmt.Errorf("desiredSign:%s <> sign:%s", desiredSign, sign), "")
}
}
msg = &CallbackMsg{
MapData: mapData,
}
returnCode := utils.Interface2String(mapData["return_code"])
if returnCode != ResponseCodeSuccess {
msg.Data = &BaseResultMsg{
ReturnCode: returnCode,
ReturnMsg: utils.Interface2String(mapData["return_msg"]),
}
} else {
reqInfo := utils.Interface2String(mapData["req_info"])
if reqInfo == "" {
sign := utils.Interface2String(mapData[sigKey])
desiredSign := a.signParam(mapData)
if desiredSign != sign {
return nil, Err2CallbackResponse(fmt.Errorf("desiredSign:%s <> sign:%s", desiredSign, sign), "")
}
}
if reqInfo != "" {
msg.MsgType = MsgTypeRefund
var refundResult *RefundResultMsg
if err = utils.Map2StructByJson(mapData, &refundResult, false); err == nil {
if reqInfo, err = a.decodeReqInfo(reqInfo); err == nil {
mv, err2 := mxj.NewMapXml([]byte(reqInfo))
if err = err2; err == nil {
reqInfoMap := mv["root"].(map[string]interface{})
if err = utils.Map2StructByJson(reqInfoMap, &refundResult.ReqInfoObj, false); err == nil {
msg.Data = refundResult
}
if reqInfo != "" {
msg.MsgType = MsgTypeRefund
var refundResult *RefundResultMsg
if err = utils.Map2StructByJson(mapData, &refundResult, false); err == nil {
if reqInfo, err = a.decodeReqInfo(reqInfo); err == nil {
mv, err2 := mxj.NewMapXml([]byte(reqInfo))
if err = err2; err == nil {
reqInfoMap := mv["root"].(map[string]interface{})
if err = utils.Map2StructByJson(reqInfoMap, &refundResult.ReqInfoObj, false); err == nil {
msg.Data = refundResult
}
}
}
} else if transactionID := utils.Interface2String(mapData["transaction_id"]); transactionID != "" {
msg.MsgType = MsgTypePay
var payResult *PayResultMsg
if err = utils.Map2StructByJson(mapData, &payResult, false); err == nil {
msg.Data = payResult
}
}
} else if transactionID != "" {
msg.MsgType = MsgTypePay
var payResult *PayResultMsg
if err = utils.Map2StructByJson(mapData, &payResult, false); err == nil {
msg.Data = payResult
}
}
if err != nil {

View File

@@ -153,6 +153,11 @@ type CreateOrderParam struct {
SceneInfo string `json:"scene_info,omitempty" xml:"scene_info,omitempty"`
}
type CloseOrderParam struct {
RequestBase
OutTradeNo string `json:"out_trade_no" xml:"out_trade_no"`
}
type CreateOrderResult struct {
ReturnCode string `json:"return_code" xml:"return_code"`
ReturnMsg string `json:"return_msg" xml:"return_msg"`
@@ -163,6 +168,7 @@ type CreateOrderResult struct {
NonceStr string `json:"nonce_str" xml:"nonce_str"`
Sign string `json:"sign" xml:"sign"`
ResultCode string `json:"result_code" xml:"result_code"`
ResultMsg string `json:"result_msg" xml:"result_msg"`
ErrCode string `json:"err_code,omitempty" xml:"err_code,omitempty"`
ErrCodeDes string `json:"err_code_des,omitempty" xml:"err_code_des,omitempty"`
@@ -195,6 +201,7 @@ type PayRefundResult struct {
NonceStr string `json:"nonce_str" xml:"nonce_str"`
Sign string `json:"sign" xml:"sign"`
ResultCode string `json:"result_code" xml:"result_code"`
ResultMsg string `json:"result_msg" xml:"result_msg"`
ErrCode string `json:"err_code,omitempty" xml:"err_code,omitempty"`
ErrCodeDes string `json:"err_code_des,omitempty" xml:"err_code_des,omitempty"`
@@ -315,12 +322,19 @@ func (a *API) AccessAPI(action string, requestParam IRequestBase) (retVal map[st
return retVal, err
}
func (a *API) checkResultAsMap(xmlStr string) (result map[string]interface{}, errLevel string, err error) {
func (a *API) parseXmlStrAsMap(xmlStr string) (result map[string]interface{}, errLevel string, err error) {
mv, err := mxj.NewMapXml([]byte(xmlStr))
if err != nil {
errLevel = platformapi.ErrLevelGeneralFail
} else {
result = mv["xml"].(map[string]interface{})
}
return result, errLevel, err
}
func (a *API) checkResultAsMap(xmlStr string) (result map[string]interface{}, errLevel string, err error) {
result, errLevel, err = a.parseXmlStrAsMap(xmlStr)
if err == nil {
returnCode := utils.Interface2String(result["return_code"])
if returnCode != ResponseCodeSuccess {
errLevel = platformapi.ErrLevelGeneralFail
@@ -344,6 +358,20 @@ func PayTime2Time(str string) (t time.Time) {
return t
}
func (a *API) mapData2Err(mapData map[string]interface{}) (err error) {
if resultCode := utils.Interface2String(mapData["result_code"]); resultCode != ResponseCodeSuccess {
err = utils.NewErrorCode(utils.Interface2String(mapData["err_code_des"]), utils.Interface2String(mapData["err_code"]))
}
return err
}
func (a *API) translateResult(mapData map[string]interface{}, dataPtr interface{}) (err error) {
if err = a.mapData2Err(mapData); err == nil && dataPtr != nil {
err = utils.Map2StructByJson(mapData, dataPtr, false)
}
return err
}
func (a *API) OrderQuery(transactionID, outTradeNo string) (orderInfo *OrderInfo, err error) {
param := &OrderQueryParam{
TransactionID: transactionID,
@@ -351,7 +379,7 @@ func (a *API) OrderQuery(transactionID, outTradeNo string) (orderInfo *OrderInfo
}
retVal, err := a.AccessAPI("pay/orderquery", param)
if err == nil {
err = utils.Map2StructByJson(retVal, &orderInfo, false)
err = a.translateResult(retVal, &orderInfo)
}
return orderInfo, err
}
@@ -359,18 +387,32 @@ func (a *API) OrderQuery(transactionID, outTradeNo string) (orderInfo *OrderInfo
func (a *API) CreateUnifiedOrder(param *CreateOrderParam) (createOrderResult *CreateOrderResult, err error) {
retVal, err := a.AccessAPI("pay/unifiedorder", param)
if err == nil {
err = utils.Map2StructByJson(retVal, &createOrderResult, false)
err = a.translateResult(retVal, &createOrderResult)
}
return createOrderResult, err
}
// 关闭订单
// https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3
// 注意订单生成后不能马上调用关单接口最短调用时间间隔为5分钟。
// 此函数好像可以重复操作,且关闭一个不存在的订单也不会报错的样
func (a *API) CloseOrder(outTradeNo string) (err error) {
retVal, err := a.AccessAPI("pay/closeorder", &CloseOrderParam{
OutTradeNo: outTradeNo,
})
if err == nil {
err = a.translateResult(retVal, nil)
}
return err
}
func (a *API) PayRefund(param *PayRefundParam) (refundResult *PayRefundResult, err error) {
if a.client.Transport == nil {
return nil, fmt.Errorf("没有配置证书,不能退款")
}
retVal, err := a.AccessAPI("secapi/pay/refund", param)
if err == nil {
err = utils.Map2StructByJson(retVal, &refundResult, false)
err = a.translateResult(retVal, &refundResult)
}
return refundResult, err
}

View File

@@ -36,8 +36,8 @@ func TestOrderQuery(t *testing.T) {
}
func TestCreateUnifiedOrder(t *testing.T) {
orderNo := "367609100BA711EAAA20186590E02977" // utils.GetUUID()
// t.Log(orderNo)
orderNo := utils.GetUUID()
t.Log(orderNo)
result, err := api.CreateUnifiedOrder(&CreateOrderParam{
Body: "这里一个测试商品",
NotifyURL: "http://callback.test.jxc4.com/wxpay/msg/",
@@ -52,6 +52,15 @@ func TestCreateUnifiedOrder(t *testing.T) {
t.Log(utils.Format4Output(result, false))
}
func TestCloseOrder(t *testing.T) {
orderNo := "5CA4BC5E22C611EA9AB9186590E02977" // utils.GetUUID()
// t.Log(orderNo)
err := api.CloseOrder(orderNo)
if err != nil {
t.Fatal(err)
}
}
func TestPayRefund(t *testing.T) {
result, err := api.PayRefund(&PayRefundParam{
TransactionID: "",