微信支付接入全流程与常见问题解决方案
又双叒叕被微信支付坑了
前几天接到个需求,要在H5页面里集成微信支付。想着这玩意儿我都做过好几次了,应该没啥问题吧?结果现实狠狠打了我的脸。
最开始遇到的问题是调用支付接口时一直报错:-1,这个错误码官方文档压根没提。折腾了半天才发现是因为签名生成有问题。
核心代码就这几行
先说解决方案,下面是完整的支付调用代码:
// 微信支付初始化
function initWeChatPay(data) {
return new Promise((resolve, reject) => {
if (typeof WeixinJSBridge === "undefined") {
document.addEventListener('WeixinJSBridgeReady', () => {
onBridgeReady(data, resolve, reject);
}, false);
} else {
onBridgeReady(data, resolve, reject);
}
});
}
function onBridgeReady(data, resolve, reject) {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
appId: data.appId, // 公众号名称
timeStamp: data.timeStamp, // 时间戳
nonceStr: data.nonceStr, // 随机串
package: data.package, // 统一下单接口返回的 prepay_id
signType: data.signType,// 签名方式
paySign: data.paySign // 支付签名
},
function(res) {
if (res.err_msg === "get_brand_wcpay_request:ok") {
resolve(true);
} else {
reject(res.err_msg);
}
}
);
}
这里我踩了个大坑:签名算法不对
重点说下签名这块,我一开始直接用了后端给的参数,但一直报错。后来试了下发现几个关键点:
- 字段顺序必须正确:微信要求按照字典序排序,不能乱来
- 大小写敏感:appId 和 appid 是不一样的
- 时间戳单位:必须是秒级时间戳
正确的签名生成代码如下:
function generateSign(params, key) {
const sortedKeys = Object.keys(params).sort();
let stringA = '';
sortedKeys.forEach(k => {
if (params[k] !== '' && params[k] != null) {
stringA += ${k}=${params[k]}&;
}
});
const stringSignTemp = stringA + key=${key};
return md5(stringSignTemp).toUpperCase();
}
支付环境检测也很重要
另一个让我头疼的问题是支付环境判断。在开发过程中发现,如果不在微信内置浏览器里打开,WeixinJSBridge 对象会是 undefined。
这里要注意,微信支付只能在微信内置浏览器中使用。为了确保支付功能正常,最好加上环境检测:
function isWeChatBrowser() {
const ua = navigator.userAgent.toLowerCase();
return /micromessenger/.test(ua);
}
if (!isWeChatBrowser()) {
alert("请在微信客户端中打开");
return;
}
后台接口对接那些事儿
说到后台接口,这里也有个坑要提醒大家。最初我们后端直接把所有参数都返回给我,我拿过来就用,结果各种报错。
后来和后端同学一起排查发现:
- 预支付订单接口需要通过服务端调用统一下单接口获取
prepay_id - 支付签名必须在服务端生成并返回
- 前端只需要负责调用支付接口即可
以下是我们最终约定的接口格式:
{
"appId": "wx1234567890abcdef",
"timeStamp": "1625436890",
"nonceStr": "randomstring123456",
"package": "prepay_id=wx20210705abcdefg",
"signType": "MD5",
"paySign": "C380BEC2BFD727A4B6845133519F3AD6"
}
还有一些小细节要注意
虽然主要问题都解决了,但还是遇到了些小状况:
- Android 和 iOS 的支付回调表现不太一样,iOS 有时会有延迟
- 用户取消支付后的处理逻辑需要特别注意,不能简单地当成失败
- 支付成功后的页面跳转需要考虑微信的安全域名限制
比如安全域名这个事,我就踩过坑。记得要把所有可能跳转的域名都配置到微信公众平台的 JS 安全域名列表里:
const API_URL = 'https://jztheme.com/api';
const SUCCESS_URL = 'https://jztheme.com/pay-success';
const FAIL_URL = 'https://jztheme.com/pay-fail';
以上是我踩坑后的总结
微信支付确实是个深坑,特别是对于新手来说。从签名算法到支付环境,从前端调用到后端接口,每个环节都可能出问题。
不过经过这次折腾,我对整个支付流程的理解更深了。虽然过程很痛苦,但解决问题后的成就感还是挺爽的。
如果你有更好的实现方案,或者遇到其他奇葩问题,欢迎在评论区交流。毕竟微信支付这种东西,谁碰谁知道有多复杂。
本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。

暂无评论