如何使用API v3接口
本篇内容介绍了"如何使用API v3接口"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
版本
jdk:1.8wechatpay-apache-httpclient:0.2.2
应用
笔者以微信小程序支付接口为例展开说明,至于小程序注册、认证、微信支付注册本文概不说明。
基础配置
1.申请商户API证书
登录微信支付后台,进入账户中心,API安全设置,如下图 申请商户证书,如下图 点击"申请证书"按钮后,弹出生成API证书申请框,如下图 根据提示下载证书工具,当前页面不要关闭,下载证书工具后打开,如下图
点击"申请证书"按钮后,进入填写商户信息界面,商户信息经测试是自动填充的,如下图 点击"下一步",进入复制请求串界面,如下图 将证书请求串进行复制,复制后回到上述微信支付后台申请API证书页面,将请求串进行复制,经测试自动帮你完成复制粘贴,请求串复制后点击"下一步"操作,进入复制证书串步骤,如下图 点击"复制证书串",将复制的证书串粘贴至证书工具中,如下图 点击"下一步"完成商户证书的申请,如下图 商户API证书已生成,点击查看证书文件夹,即可查看证书信息,如下图 在微信支付商户后台可获取商户API证书序列号及证书有效期,如下图
2.设置接口密钥
设置API密钥,现阶段由于微信支付原先老接口并未全部升级至API v3版,涉及新老接口共存的情况,所以API密钥及APIV3密钥都需进行设置,新老接口请查阅微信支付开发文档 API v2老版本密钥设置 API v3密钥设置
3.下载平台证书
微信平台证书下载,查阅开发文档,微信已提供证书下载工具 如下图
关注本文末尾微信公众号,回复"666"获取常用开发工具包,内含常用开发组件及微信证书下载工具,节省下载时间。
下载平台证书至本地,执行命令
必需参数有:商户的私钥文件,即 -f (商户API证书中apiclient_key.pem文件路径)证书解密的密钥,即 -k (微信支付后台设置的APIv3密钥)商户号,即 -m (微信支付商户号,可在微信支付后台查阅)保存证书的路径,即 -o (微信平台证书保存路径)商户证书的序列号,即 -s (商户API证书,即上述第一步申请商户API证书序列号)非必需参数有:微信支付证书,用于验签,即 -c完整命令如下java -jar CertificateDownloader-1.1.jar -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath}
至此基础配置参数已准备就绪
接口实测
在请求接口之前先了解下接口中一些参数概念,首次接触最容易搞混的就是商户API证书和平台证书,如下图
微信支付API官方客户端
以往老吐槽微信支付接口文档不友好,没有sdk,现在API v3版本给你提供了一个客户端,这点还是可以点赞的,对于开发人员来说,demo代码直接拿过来,更改下配置参数就可以跑通,那简直是对程序员莫大的关怀,这方面阿里相对做的比较好
talk is cheap, show me the code
1.客户端
以post请求方式说明,get请求类似
private static String basePostRequest(String requestUrl,String requestJson) { CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; HttpEntity entity = null; try { PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8"))); X509Certificate wechatpayCertificate = PemUtil.loadCertificate(new ByteArrayInputStream(certificate.getBytes("utf-8"))); ArrayListlistCertificates = new ArrayList<>(); listCertificates.add(wechatpayCertificate); httpClient = WechatPayHttpClientBuilder.create() .withMerchant(mchId, mchSerialNo, merchantPrivateKey) .withWechatpay(listCertificates) .build(); HttpPost httpPost = new HttpPost(requestUrl); // NOTE: 建议指定charset=utf-8。低于4.4.6版本的HttpCore,不能正确的设置字符集,可能导致签名错误 StringEntity reqEntity = new StringEntity(requestJson, ContentType.create("application/json", "utf-8")); httpPost.setEntity(reqEntity); httpPost.addHeader("Accept", "application/json"); response = httpClient.execute(httpPost); entity = response.getEntity(); return EntityUtils.toString(entity); } catch (Exception e) { e.printStackTrace(); } finally { // 关闭流 } return null; }
方法中涉及参数说明
PemUtil.java类为com.wechat.pay.contrib.apache.httpclient.util.PemUtil
请求签名及应答签名校验该客户端均已帮你处理好,心中对微信支付开发文档有了一点点好感。根据具体接口方法传入接口地址及相应接口参数JSON数据即可完成接口联调测试。
2.支付调起参数签名
以小程序调起支付接口为例,简单说明参数签名方式,先看下文档中签名是怎么说的,如下图
/** * 微信支付-前端唤起支付参数 * prepay_id=wx201410272009395522657a690389285100 * @param packageStr 预下单接口返回数据 预支付交易会话标识 prepay_id * @return */ public static MapcreatePayParams(String packageStr) { Map resultMap = new HashMap<>(); String nonceStr = StringUtil.getUUID(); Long timestamp = System.currentTimeMillis() / 1000; String message = buildMessage(timestamp, nonceStr, packageStr); String signature = null; try { signature = sign(message.getBytes("utf-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } resultMap.put("appId", appId); resultMap.put("timeStamp",timestamp.toString()); resultMap.put("nonceStr",nonceStr); resultMap.put("package",packageStr); resultMap.put("signType","RSA"); resultMap.put("paySign",signature); return resultMap; } /** * 微信支付-前端唤起支付参数-签名 * @param message 签名数据 * @return */ public static String sign(byte[] message) { try{ Signature sign = Signature.getInstance("SHA256withRSA"); sign.initSign(getPrivateKey(keyFilePath)); sign.update(message); return Base64.getEncoder().encodeToString(sign.sign()); } catch(Exception e) { e.printStackTrace(); } return null; } /** * 微信支付-前端唤起支付参数-构建签名参数 * @param nonceStr 签名数据 * @return */ public static String buildMessage(long timestamp, String nonceStr, String packageStr) { return appId + "\n" + timestamp + "\n" + nonceStr + "\n" + packageStr + "\n"; } /** * 微信支付-前端唤起支付参数-获取商户私钥 * * @param filename 私钥文件路径 (required) * @return 私钥对象 */ public static PrivateKey getPrivateKey(String filename) throws IOException { String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8"); try { String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll("\\s+", ""); KeyFactory kf = KeyFactory.getInstance("RSA"); return kf.generatePrivate( new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey))); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("当前Java环境不支持RSA", e); } catch (InvalidKeySpecException e) { throw new RuntimeException("无效的密钥格式"); } }
方法中涉及参数说明
3.回调通知
回调通知涉及验签及解密
回调数据获取
String body = request.getReader().lines().collect(Collectors.joining());
验签
/** * 回调验签 * https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml * @param wechatpaySerial 回调head头部 * @param wechatpaySignature 回调head头部 * @param wechatpayTimestamp 回调head头部 * @param wechatpayNonce 回调head头部 * @param body 请求数据 * @return */ public static boolean responseSignVerify(String wechatpaySerial, String wechatpaySignature, String wechatpayTimestamp, String wechatpayNonce, String body) { FileInputStream fileInputStream = null; try { String signatureStr = buildMessage(wechatpayTimestamp, wechatpayNonce, body); Signature signer = Signature.getInstance("SHA256withRSA"); fileInputStream = new FileInputStream(weixin_platform_cert_path); X509Certificate receivedCertificate = loadCertificate(fileInputStream); signer.initVerify(receivedCertificate); signer.update(signatureStr.getBytes(StandardCharsets.UTF_8)); return signer.verify(Base64.getDecoder().decode(wechatpaySignature)); } catch (Exception e ) { e.printStackTrace(); } finally { if (fileInputStream != null) { try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return false; } /** * 回调验签-加载微信平台证书 * @param inputStream * @return */ public static X509Certificate loadCertificate(InputStream inputStream) { try { CertificateFactory cf = CertificateFactory.getInstance("X509"); X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); cert.checkValidity(); return cert; } catch (CertificateExpiredException e) { throw new RuntimeException("证书已过期", e); } catch (CertificateNotYetValidException e) { throw new RuntimeException("证书尚未生效", e); } catch (CertificateException e) { throw new RuntimeException("无效的证书", e); } } /** * 回调验签-构建签名数据 * @param * @return */ public static String buildMessage(String wechatpayTimestamp, String wechatpayNonce, String body) { return wechatpayTimestamp + "\n" + wechatpayNonce + "\n" + body + "\n"; }
方法中涉及参数说明
解密
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtmlAesUtil wxAesUtil = new AesUtil(apiv3.getBytes());String jsonStr = wxAesUtil.decryptToString("associated_data".getBytes(),"nonce".getBytes(),"ciphertext");
方法中涉及参数说明
"如何使用API v3接口"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!