调整AccessPlatformAPIWithRetry中的调试输出信息
+wxpayapi.CloseOrder
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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: "",
|
||||
|
||||
Reference in New Issue
Block a user