Appearance
微信 JSAPI 支付
前端只需要使用如下 API 唤起支付即可,参数由后段提供
H5 如何调用
https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml
ts
function onBridgeReady() {
WeixinJSBridge.invoke(
"getBrandWCPayRequest",
{
appId: "wx2421b1c4370ecxxx", //公众号ID,由商户传入
timeStamp: "1395712654", //时间戳,自1970年以来的秒数
nonceStr: "e61463f8efa94090b1f366cccfbbb444", //随机串
package: "prepay_id=wx21201855730335ac86f8c43d1889123400",
signType: "RSA", //微信签名方式:
paySign:
"oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq/xDg==", //微信签名
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
}
);
}其他代码
ts
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener("WeixinJSBridgeReady", onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent("WeixinJSBridgeReady", onBridgeReady);
document.attachEvent("onWeixinJSBridgeReady", onBridgeReady);
}
} else {
onBridgeReady();
}以下为 server 内容
接入流程

签名
微信支付 API v3 请求都需要签名,签名不通过会被拒绝,并返回 401 Unauthorized。
官方文档:https://pay.weixin.qq.com/docs/merchant/development/interface-rules/signature-generation.html
准备条件
- 微信支付商户号 / mchid
- 证书序列号 / serial_no
- API 证书(超级管理员账号获取,压缩包中)
签名串格式:
HTTP请求方法\n
URL\n
请求时间戳\n
请求随机串\n
请求报文主体\n示例:
GET\n
/v3/certificates\n
1554208460\n
593BEC0C930BF1AFEB40B4A08C8FB242\n
\n需要注意的是,URL 中如果有 params,是需要加 ? 的
微信会拒绝很久之前的请求,所以请求时间戳最好取当前。并且是秒,不是毫秒。
签名计算 示例
js
const { createSign, createPrivateKey } = require("crypto");
const privateKey = createPrivateKey(`-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAptpm+qvIDCh/9wjU26SQCK26ogYkBhDrYxnAaw2JbbBsp1oD bHKk+1r381NeBUG2HEFAuU+Fr72u5ot3yKdzoF/FajAzQNKnm569/D3upKoi8mYB aST15Uig8j8qoUW1U217LL0jEHlSnHV3lcaDTXqDpTRR4Bfz9IqOgJgFZ8/oTfEo mSrjrLYef81Eyxr7ZIMQXEKKEK7V4UXKS0+/fDsiG/cXidhzt8UbTL9vqXqxM2+I DImyO+FAc/tkBG55LmzxPto1Nq0WbnZzRM/wTzrd0I/8NlevxtFbphg4evlHjFNI 7+GrqR87ViEwuAJJ9Je5QQjct5YJfFRWiZ5CMQIDAQABAoIBAGBi/GhEgezcHIg1 ltlHaFlLGuxsRbUnYwM9phVxnXk7GJlYe2/TjpERjPkIqOC6hBwwadZjJORP3FCc Mtc8PKRhjuZ377O7vU0915x2nnyLOGL1IE2AJ3iLi0ZFzTea0FPgg+5lWHM00s9F YI6qPcGtS41M+xtMWwZiYE3TBBRibHiY8ugGyaNAhiMKehyW05uApjlIF55wwCGx BkyESJpGRR/6853iHke6Ge+xVcMa9QmQdoH0QqL/8kT28PL568mJJr0Ow/83t4+d Pe70YPzKAxgUnaDsHJqO+b8qH69AEs8rTI5h2Mon6pH+bJT66KUoiXhn+Kf+4LSs henRP10CgYEA1QJSfuFOWVRjrg3N/rAIc/Ak84BTZavbyrkqBSuoTs9i/nMI/hOz VxpDntg7Bx2Tctl6sZO3GioTxKdc/YYaTKci1TKBbeginpsqEQVgwkMCy8HpvUmR fyAMqLwZC4h9+j+NiZtuoFJDTCgv+WYbasX+kWYEUM21bnSYuO7yEQsCgYEAyIdP r9uzqPgzN34Tmx+CNTa16VjhBh+zkBtXRLDLhWBeIYxoYNJARD98Pb1XZdvpkZZW Sk7MfaKo2/DomzyyyB/MbHWwAdFi3yb4y7uMJfyC1MzdUSNN3Vp579hJxHkJ+nN4 Ys76yfcEeVOLnvUT1Z0KKCdIWRdT1Lgi+X1itzMCgYBJUXlPzwGG4fNFj97d0X23 Wmt9nSgXkOYgi0eZbAOMzPmIF9R6kBFk49dur4Lx2g5Ms+r1gKC/0sfnIqxxX11i EQ1+UNoYGJUB/uql3TIG68XkmKR50P7RwRhaZBRC0gJ6xrFTMjsL2ATuC88niyvY vrn3FiRaI9RVZrDCxwxvLQKBgEXW4okEAqGBuAzGqztmkOnJoTehDdYdKmOxMgap cGiGdKJIjX3THDDoz3ONQyglnEZpTqpYoV3MTfU0BT8zt6x9bqwDnQY1D7NalmIW cqw0Mri8lQQSQKcsQLWo5aA466G/n5kCL1Qx5OwAjesRvhOyuvvbGpZ0ymyWqQ+t fLkDAoGATcul1L8y5D/wNVP1GXbXMZfBsFP3bbqy8c+Ashm6g8OLm2mGNntd5Z6h 1KkID7Yksh+dZ6t7XaPBtGACXX5Eryr537JVvdX8hAVCp5HVtaN/9VBVP8Ka2e4s VS/xeNgOMQ7uzhRPBJ8HiTmdI1nHhDnYQpGiBgQn0Z5RAkSvFMk=
-----END RSA PRIVATE KEY-----`);
function signature(conf) {
const {
algorithm = "sha256",
data,
output_format = "base64",
privateKey,
} = conf;
const sign = createSign(algorithm);
sign.update(data);
sign.end();
return sign.sign(privateKey, output_format);
}
function getWxSignature(param) {
const { method, url, body = "" } = param;
const timestamp = "1554208460";
const nonce_str = "593BEC0C930BF1AFEB40B4A08C8FB242";
const data = `${method}\n${url}\n${timestamp}\n${nonce_str}\n${body}\n`;
console.log(data);
const sign = signature({
data,
privateKey,
});
return {
timestamp,
nonce_str,
signature: sign,
};
}
const result = getWxSignature({
method: "GET",
url: "/v3/refund/domestic/refunds/123123123123",
});
console.log(result.signature);
console.log(
"Lc9VXxmeonkdV8Xk9tmigQFLhl0vRWTerdmoRu01aAnYwIrD/5nsSwE1WlmZGLRlAFTNQ3QsMa0+VRDlJp1Wp5p0nO8EK68b5sJBbjouxaFciIfq1zfDWWz+jqhcMoKXI1A6dPm1AW7D4d30WsMTNzp6g23OXakIsh9LO3lUmwvTuE0BY8ncf6tNGk4wKmvXwERd/ZpoQY3MAVKz+Nakwc+2XBmzT66KcUehU5kr4IvGa/lEU5RZb/q00zP9VLdBhC/jQSX3X1UcJLCtEc4gTmib4tnmAT+bHF/e17ZAuxDNcx6rqT8gNEXqaJGG+1OflMSTU2tpyG65G4dMKdFcoA=="
);问题
输入源“/appid”映射到字段“公众号 ID”必填性规则校验失败,此字段为必填项
{"description":"测试支付","out_trade_no":"5e19a33065b842a7bb95bb07db623a8d","appid":"wxa9462c49dd468b45","mchid":"1690694541","notify_url":"https://www.cqzmi.com/api/v2/wx/pay/notify","amount":{"total":"0.01"},"payer":{"openid":"oHeVG6gxIqnkADyR1jjxb8VzY5PU"}}Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1690694541",nonce_str="470267f053bb4d1fb75482db8368a45c",signature="CDpRDPn3aoOml7dT2Y0HBt0dk209q8SB1FvSGBBzTcgQ9kCgsZWZWqvaCgGgyFMAsLcY6tGADB+8DLIOInQEHL+Qu/nFXuz31dmdCGYtq7Ubs9uvKOMSQrFLkhDiwAbR1lMka2uQs/vn3l1P3N1ypwanBY8XVFY3beBq0IbUEnZWFnbkx7AoeC1BKWVZs3vQtkp69LDj8EPWAPRC+V5cRfsuLVBH89jM3RVoVq5pMcchK7ygpu+aDyJTt19TmvKf2+IiBxx4HmlpaktUl2Z0DG48k8VnIdw9J26tQbCsdBs0bHWe+AEg8dVGuX2mJvdUqSwwzJcQwPMl/lfHHKw+Bg==",timestamp="1730618129",serial_no="70331DBACB69CC4A05C10DA714C455F976B42E9A"\r\n