電商收付通系列⑧,合單下單之支付通知

大家好,我是小悟

1、介紹

用戶支付完成后,微信會把相關(guān)支付結(jié)果和用戶信息發(fā)送給清算機(jī)構(gòu),清算機(jī)構(gòu)需要接收處理后返回應(yīng)答成功,然后繼續(xù)給異步通知到下游從業(yè)機(jī)構(gòu)。

對后臺通知交互時,如果微信收到應(yīng)答不是成功或超時,微信認(rèn)為通知失敗,微信會通過一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。

image.png

2、對通知數(shù)據(jù)進(jìn)行解密

系統(tǒng)對于開啟結(jié)果通知的內(nèi)容一定要做簽名驗(yàn)證,并校驗(yàn)通知的信息是否與我們的信息一致,防止數(shù)據(jù)泄露導(dǎo)致出現(xiàn)“假通知”,造成資金損失。

支付通知和獲取微信支付平臺證書一樣,需要對獲取到的內(nèi)容進(jìn)行解密,解密規(guī)則一樣,AesUtils這個解密工具類參考官方文檔給的demo。

String result = new String(outSteam.toByteArray(), StandardCharsets.UTF_8);

System.out.println("微信支付回調(diào)返回參數(shù)result:=====" + result);

JSONObject json = JSONObject.parseObject(result);

System.out.println("微信支付回調(diào)返回參數(shù)json:=====" + json);

JSONObject resourceRes = json.getJSONObject("resource");

System.out.println("微信支付回調(diào)返回參數(shù)resourceRes:=====" + resourceRes);

AesUtils aesUtil = new AesUtils("APIv3密鑰".getBytes(StandardCharsets.UTF_8));

String resourceStr = aesUtil.decryptToString(resourceRes.getString("associated_data").getBytes(StandardCharsets.UTF_8),
        resourceRes.getString("nonce").getBytes(StandardCharsets.UTF_8),
        resourceRes.getString("ciphertext"));
JSONObject resourceJson = JSONObject.parseObject(resourceStr);

System.out.println("微信支付回調(diào)返回參數(shù)resourceJson明文:=====" + resourceJson);
image.png

3、避免重復(fù)下發(fā)通知

同樣的通知可能會多次發(fā)送給我們自身系統(tǒng),所以我們需要做好正確處理重復(fù)通知的邏輯。當(dāng)自身系統(tǒng)收到通知進(jìn)行處理時,先檢查對應(yīng)業(yè)務(wù)數(shù)據(jù)的狀態(tài),并判斷該通知是否已經(jīng)處理。如果未處理,則再進(jìn)行處理,如果已處理,則直接返回結(jié)果成功。

為盡可能提高通知的成功率,微信側(cè)會重復(fù)發(fā)起通知,為了避免這樣的結(jié)果影響到處理業(yè)務(wù)邏輯,我們需要返回一定格式的響應(yīng)數(shù)據(jù)給微信,如下,親測有效。

Map<String,Object> res = new HashMap<String, Object> ();
res.put("code","SUCCESS");
res.put("message","OK");

res.put("code","ERROR_NAME");
res.put("message",e.getMessage());
image.png

4、支付通知接口

在合單支付的notify_url參數(shù)字段傳入"https://xxx/combineNotify"即可

@RequestMapping(value = "/combineNotify", method = {RequestMethod.POST})
public Map<String,Object> combineNotify(HttpServletRequest request) {
    Map<String,Object> res = new HashMap<String, Object> ();
    try {
        // 創(chuàng)建支付應(yīng)答對象
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        outSteam.close();
        inStream.close();

        String result = new String(outSteam.toByteArray(), StandardCharsets.UTF_8);

        System.out.println("微信支付回調(diào)返回參數(shù)result:=====" + result);

        JSONObject json = JSONObject.parseObject(result);

        System.out.println("微信支付回調(diào)返回參數(shù)json:=====" + json);

        JSONObject resourceRes = json.getJSONObject("resource");

        System.out.println("微信支付回調(diào)返回參數(shù)resourceRes:=====" + resourceRes);

        AesUtils aesUtil = new AesUtils("APIv3密鑰".getBytes(StandardCharsets.UTF_8));

        String resourceStr = aesUtil.decryptToString(resourceRes.getString("associated_data").getBytes(StandardCharsets.UTF_8),
                resourceRes.getString("nonce").getBytes(StandardCharsets.UTF_8),
                resourceRes.getString("ciphertext"));

        JSONObject resourceJson = JSONObject.parseObject(resourceStr);

        System.out.println("微信支付回調(diào)返回參數(shù)resourceJson明文:=====" + resourceJson);

        //驗(yàn)證微信支付返回簽名
        String Wtimestamp = request.getHeader("Wechatpay-Timestamp");
        String Wnonce = request.getHeader("Wechatpay-Nonce");
        String Wsign = request.getHeader("Wechatpay-Signature");

        System.out.println("Wtimestamp:"+Wtimestamp+",Wnonce:"+Wnonce+",Wsign:"+Wsign);
        //拼裝待簽名串
        StringBuffer ss =new StringBuffer();
        ss.append(Wtimestamp).append("\n");
        ss.append(Wnonce).append("\n");
        ss.append(result).append("\n");

        //驗(yàn)證簽名
        if(SignUtils.v3VerifyRSA(ss.toString(), Base64.decodeBase64(Wsign.getBytes()), "/data/tomcat/webapps/ROOT/wechat_pay_platform_4927801AFE1D0A15A2E4491C9C13E6414B17AFCC.pem")) {
            System.out.println("微信支付回調(diào)簽名驗(yàn)證成功");
        }else {
            System.out.println("微信支付回調(diào)簽名驗(yàn)證失敗");
        }
        res.put("code","SUCCESS");
        res.put("message","OK");
    } catch (GeneralSecurityException e) {
        e.printStackTrace();
        res.put("code","ERROR_NAME");
        res.put("message",e.getMessage());
    } catch (IOException e) {
        e.printStackTrace();
        res.put("code","ERROR_NAME");
        res.put("message",e.getMessage());
    } catch (Exception e) {
        e.printStackTrace();
        res.put("code","ERROR_NAME");
        res.put("message",e.getMessage());
    }
    return res;
}

image.png

5、結(jié)果

微信支付回調(diào)返回參數(shù)json:====={"summary":"支付成功","event_type":"TRANSACTION.SUCCESS","create_time":"2020-03-24T18:07:42+08:00","resource":{"associated_data":"transaction","ciphertext":"6XMaa17DRH9uKYuRJneC3wy6ihGiPquKGaCsCScBtxxMY5PLHEeLPl3kBgH/Yes+FOrLh92zsbQa85OIAtnc7eqlLpWb1uiP3jJhglmjzul35WK+naUsxzKLDgUFnUcyfV1PTM287QEFRIC+jvbwHK82lpELOEUCnBx0/ompQM3fzxWQczlw3CvPWTciSgy8XUqui5owvXxkbrKwruIEfigY/LOByXW0w26jX7hEKLjAghdD1NvIgFhkKf3MkbGduNiDsTn1V5z9hzoWR2MwJI/NZFRpsdr9QmxkSiGwf0FzqnOhCLsjntXAKru89CsdWyfznl2BRdbBYF+4ZRqRgbMr+sROQ9TNXVMYjNFeeyXdnpM0BNAdOIKCMI7eBkHsyARgKkXVVlAUkInatbkO/IyIUyJ4PaUJJAYkbxsgIrh1XXpDMfmR8lVpDT8FfumNebL4cILpcOCTfJ+4mn8Es8xKdOiGgEH6ZVqYrjWVkUwBwAHel4xGdat8i80wlIUh2q1z9IN0QggIHp4lCbnSeyeqiTh3WwFiM6Yv/1pHaYde/JSRo0fmdIhFrPGR383GXWqCkQK7yoUydu8e5Dq4qY1GPI9VcaAkMG68sVl762w3Us5/VvO41+nX1BlhFWNsg0VqDLHRvWL+I/gsbXHffub34Je2UF1e0mL7ghmFEXT6k6fQ4FYvSEPQ8CI3KaxMW1RJfUBRqpzKfrzkfi6EgVDAKXQvJc4HvwSmdix8UkRXysger/yfzugVAqwUV2SC6qm+m29MOHGgb37fCaL5fJOnXkvBeb7suYsT2RbyIvoA","original_type":"transaction","nonce":"qyzVVgtmQ0fk","algorithm":"AEAD_AES_256_GCM"},"resource_type":"encrypt-resource","id":"7b3b0fa6-a627-59c1-0733-2606ec31153c"}
微信支付回調(diào)返回參數(shù)resourceJson明文:====={"combine_appid":"wxd352ef315ac365bd","sub_orders":[{"transaction_id":"4323220200001484847904033204","amount":{"payer_amount":1,"total_amount":1,"currency":"CNY","payer_currency":"CNY"},"mchid":"1915696108","trade_state":"SUCCESS","out_trade_no":"out_trade_no2_1585030201441","bank_type":"OTHERS","trade_type":"JSAPI","attach":"123&456&789","success_time":"2020-03-24T18:07:43+08:00","sub_mchid":"1564468071"}],"combine_payer_info":{"openid":"ofMy16jrqy7Z8pS23M5JI4SkKvwc"},"combine_out_trade_no":"out_trade_no1_1504430158999","combine_mchid":"1811569960","scene_info":{"device_id":"POS1:12"}}
Wtimestamp:1546844504,Wnonce:jXQ70fE0SepL62SNpUhduNCooXF2RseC,Wsign:m2QZupx0hp3fPmfAfYD35FoYK+o1DOzWQs8vkeGTiFY68JHkIlx1cx825sPbW/AHu5xsQ4nlOt4BZZ0Q4Z6szqYgxJUZe/JR0OXNtoG0yHq0m5teVLoFY5eEAuY3szAPC5RIsUOs0ByXP62KEiNNiw7sYbdVXDar4MkKLho7NY6sjaigRQZeSGvsV0q0TIy1HTQTR9otAJ5lnibwbheecXaCLvvkvHGr/kDPHkvnP1fIzVzeIM32VDTf9L4/k7vN4zdgd4R73Y/6hmk8vyTsB+VfciqUpDUQ0rC0SigGzaLukawRK+S3r4XBe1nNiM0jVTKIe5l7s8BO9THd+gwI6A==
微信支付回調(diào)簽名驗(yàn)證成功
image.png

您的一鍵三連,是我更新的最大動力,謝謝

山水有相逢,來日皆可期,謝謝閱讀,我們再會

我手中的金箍棒,上能通天,下能探海

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容