1. 微信支付V3接口的核心优势
微信支付V3接口相比老版本最大的改进是采用了更安全的RSA签名算法替代了之前的MD5签名。实测下来,RSA签名能有效防止数据篡改和伪造请求,我用过V2和V3两个版本,V3在安全性上确实更胜一筹。
另一个重大改进是证书自动更新机制。在V2时代,我们需要手动下载和更换API证书,经常遇到证书过期导致支付中断的情况。现在V3接口通过平台证书自动轮换,系统会自动获取最新证书,省去了人工维护的麻烦。记得去年双十一大促时,我们的V2证书突然过期,差点造成线上事故,后来紧急联系微信支付技术客服才解决。
V3接口还优化了回调通知机制。现在支持JSON格式的数据交互,比原来的XML更易解析。通知报文也增加了敏感信息加密,比如用户手机号会进行加密处理,这对电商类小程序特别重要,能避免用户隐私泄露的风险。
2. 开发前的准备工作
2.1 商户号与小程序绑定
首先需要登录微信支付商户平台,在"产品中心"申请开通JSAPI支付权限。这里有个坑要注意:虽然小程序支付和JSAPI支付使用相同接口,但开通时一定要选择"小程序支付场景",否则后面调用会报错。
绑定小程序APPID时,建议使用超级管理员账号操作。我遇到过普通开发者账号没有绑定权限的情况,来回折腾了好几天。绑定完成后,记下这几个关键参数:
- 小程序APPID
- 商户号(MCHID)
- APIv3密钥(32位随机字符串)
2.2 密钥与证书管理
在"账户中心"-"API安全"中设置APIv3密钥,这个密钥用于敏感数据加密和回调报文解密。建议使用密码生成器创建高强度密钥,不要使用简单字符串。
接下来要获取商户API证书:
- 在"账户中心"-"API安全"下载证书工具
- 生成请求串并提交
- 下载包含私钥的PKCS#12格式证书
这里有个实用技巧:把私钥密码和证书文件妥善保存,建议使用1Password等工具管理。我曾经不小心删除了证书文件,结果只能重新申请,导致线上支付中断了2小时。
3. 后端支付接口实现
3.1 下单接口实现
先看Java代码示例,使用微信支付官方SDK:
public PrepayResponse createOrder(OrderRequest request) { // 构建请求对象 PrepayRequest prepayRequest = new PrepayRequest(); Amount amount = new Amount(); amount.setTotal(request.getAmount().multiply(new BigDecimal(100)).intValue()); prepayRequest.setAmount(amount); prepayRequest.setAppid(wxConfig.getAppId()); prepayRequest.setMchid(wxConfig.getMchId()); prepayRequest.setDescription(request.getDescription()); prepayRequest.setNotifyUrl(wxConfig.getNotifyUrl()); prepayRequest.setOutTradeNo(generateOrderNo()); // 设置支付用户 Payer payer = new Payer(); payer.setOpenid(request.getOpenid()); prepayRequest.setPayer(payer); // 调用接口 JsapiService service = new JsapiService.Builder() .config(rsaAutoCertificateConfig) .build(); return service.prepay(prepayRequest); }关键参数说明:
total金额单位是分,需要将元转分outTradeNo商户订单号要保证唯一性notifyUrl回调地址必须支持HTTPS
3.2 支付回调处理
回调验签是支付系统最关键的环节之一。这是处理回调的完整流程:
@PostMapping("/notify") public String paymentNotify(HttpServletRequest request) { // 获取通知头信息 String signature = request.getHeader("Wechatpay-Signature"); String nonce = request.getHeader("Wechatpay-Nonce"); String timestamp = request.getHeader("Wechatpay-Timestamp"); String serial = request.getHeader("Wechatpay-Serial"); // 构造验签参数 RequestParam params = new RequestParam.Builder() .serialNumber(serial) .nonce(nonce) .signature(signature) .timestamp(timestamp) .body(IOUtils.toString(request.getInputStream())) .build(); // 验签并解密 NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig); Transaction transaction = parser.parse(params, Transaction.class); // 处理业务逻辑 if(transaction.getTradeState() == TradeStateEnum.SUCCESS) { orderService.processPayment(transaction); } return "{\"code\": \"SUCCESS\"}"; }注意点:
- 必须验证签名防止伪造请求
- 处理逻辑要加锁防止重复通知
- 返回HTTP 200状态码和SUCCESS响应
4. 前端支付流程
小程序端调用支付相对简单:
wx.requestPayment({ timeStamp: res.timeStamp, nonceStr: res.nonceStr, package: res.package, signType: 'RSA', paySign: res.paySign, success: () => { // 建议查询后台确认支付状态 this.checkOrderStatus(); }, fail: (err) => { console.error('支付失败', err); } })常见问题处理:
get_brand_wcpay_request:fail错误通常是因为package格式不正确- 支付成功后建议查询后台确认状态,不要仅依赖前端回调
5. 安全防护策略
5.1 防重放攻击
V3接口通过nonce_str和timestamp防止重放攻击。建议在服务端也做补充验证:
// 校验时间戳 long requestTime = Long.parseLong(timestamp); if(Math.abs(System.currentTimeMillis()/1000 - requestTime) > 300) { throw new RuntimeException("请求已过期"); } // 校验随机串 if(nonceCache.exists(nonceStr)) { throw new RuntimeException("重复请求"); } nonceCache.add(nonceStr, 300); // 缓存5分钟5.2 敏感数据加密
对于用户手机号等敏感信息,建议使用微信支付提供的加密工具:
// 加密示例 WechatPayEncryptor encryptor = new WechatPayEncryptor(rsaAutoCertificateConfig); String cipherText = encryptor.encrypt(phoneNumber); // 解密示例 String plainText = encryptor.decrypt(cipherText);5.3 订单状态管理
支付系统要处理好各种异常情况:
- 设置订单超时时间(建议30分钟)
- 支付成功后库存预占
- 未支付订单自动关闭
- 对账机制保证数据一致性
6. 常见问题排查
问题1:调用下单接口返回"签名错误"
解决方案:
- 检查商户API密钥是否正确
- 确认签名算法使用RSA
- 验证参数名大小写是否正确
- 使用微信支付签名验证工具调试
问题2:支付回调接收不到
解决方案:
- 检查notify_url是否外网可访问
- 确认服务器没有防火墙拦截
- 验证回调接口是否返回正确响应
- 在商户平台手动发起测试通知
问题3:证书相关错误
解决方案:
- 确保证书未过期
- 检查证书序列号配置
- 验证证书与商户号匹配
- 检查证书文件权限
我在实际项目中遇到过最棘手的问题是证书自动更新失败,后来发现是服务器时间不同步导致的。建议在服务器上配置NTP时间同步服务,这个小细节很容易被忽略。