大家好,我是小悟


1、介绍

用户支付完成后,微信会把相关支付结果和用户信息发送给清算机构,清算机构需要接收处理后返回应答成功,然后继续给异步通知到下游从业机构。

对后台通知交互时,如果微信收到应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。

电商收付通系列⑧,合单下单之支付通知_微信支付


2、对通知数据进行解密

系统对于开启结果通知的内容一定要做签名验证,并校验通知的信息是否与我们的信息一致,防止数据泄露导致出现“假通知”,造成资金损失。

支付通知和获取微信支付平台证书一样,需要对获取到的内容进行解密,解密规则一样,AesUtils这个解密工具类参考官方文档给的demo。

String result = new String(outSteam.toByteArray(), StandardCharsets.UTF_8);// 获取微信调用我们notify_url的返回信息

System.out.println("微信支付回调返回参数result:=====" + result);

JSONObject json = JSONObject.parseObject(result);

System.out.println("微信支付回调返回参数json:=====" + json);

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

System.out.println("微信支付回调返回参数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("微信支付回调返回参数resourceJson明文:=====" + resourceJson);

电商收付通系列⑧,合单下单之支付通知_微信支付_02


3、避免重复下发通知

同样的通知可能会多次发送给我们自身系统,所以我们需要做好正确处理重复通知的逻辑。当自身系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已经处理。如果未处理,则再进行处理,如果已处理,则直接返回结果成功。

为尽可能提高通知的成功率,微信侧会重复发起通知,为了避免这样的结果影响到处理业务逻辑,我们需要返回一定格式的响应数据给微信,如下,亲测有效。

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());

电商收付通系列⑧,合单下单之支付通知_微信支付_03


4、支付通知接口

在合单支付的notify_url参数字段传入" 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 {
// 创建支付应答对象
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("微信支付回调返回参数result:=====" + result);

JSONObject json = JSONObject.parseObject(result);

System.out.println("微信支付回调返回参数json:=====" + json);

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

System.out.println("微信支付回调返回参数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("微信支付回调返回参数resourceJson明文:=====" + resourceJson);

//验证微信支付返回签名
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");

//验证签名
if(SignUtils.v3VerifyRSA(ss.toString(), Base64.decodeBase64(Wsign.getBytes()), "/data/tomcat/webapps/ROOT/wechat_pay_platform_4927801AFE1D0A15A2E4491C9C13E6414B17AFCC.pem")) {
System.out.println("微信支付回调签名验证成功");
}else {
System.out.println("微信支付回调签名验证失败");
}
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;
}

电商收付通系列⑧,合单下单之支付通知_微信支付_04


5、结果

微信支付回调返回参数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"}
微信支付回调返回参数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==
微信支付回调签名验证成功


您的一键三连,是我更新的最大动力,谢谢

山水有相逢,来日皆可期,谢谢阅读,我们再会

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