纯前端JS实现微信H5支付(微信外浏览器)
H5支付文档 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_20&index=1
1.发送请求所需要的参数
/* 微信后台 设置的key 怎么拿到key https://jingyan.baidu.com/article/c1465413f093870bfcfc4c82.html */ let key = "ORM1NEK98XXXXXX3JJAITO6EB14W274ZH"; /* 支付必要参数 */ let h5Obj = { appid: "wxddxx8xx48c19xxxsdsbdcb", //appid body: "xx-商品", //商品描述 mch_id: "1579347061", //商户号 nonce_str: randomString(), //随机字符串,不长于32位。 notify_url: "https://www.baidu.com/", //接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。 out_trade_no: randomString(), // 订单号 spbill_create_ip: ip, //用户的ip地址 本地不影响 127.0.0.1 total_fee: total, //价格 trade_type: "MWEB", // h5为MWEB 固定 scene_info: '{"h5_info":{"type":"Wap","wap_url":"支付的域名www.baidu.com","wap_name":"订单"}}', // 信息 };
2.用户IP地址获取
// 这里使用的是souhu的 发送GET请求到 保存IP即可 let url = 'https://pv.sohu.com/cityjson?ie=utf-8'
3.如何进行sign签名?
// 1排序(ASCII) let reStr = sortStr(h5Obj, false, key); // 2 签名方法 获取签名 let sign = nodeMd5(reStr).toUpperCase(); // 3设置要发送的xml参数;sign放在后面 let formData = `<xml> <appid>${h5Obj.appid}</appid> <body>${h5Obj.body}</body> <mch_id>${h5Obj.mch_id}</mch_id> <nonce_str>${h5Obj.nonce_str}</nonce_str> <notify_url>${h5Obj.notify_url}</notify_url> <out_trade_no>${h5Obj.out_trade_no}</out_trade_no> <spbill_create_ip>${h5Obj.spbill_create_ip}</spbill_create_ip> <total_fee>${h5Obj.total_fee}</total_fee> <trade_type>${h5Obj.trade_type}</trade_type> <scene_info>${h5Obj.scene_info}</scene_info> <sign>${sign}</sign> </xml>`; return { h5Obj, formData, };
(1).排序方法(根据ASCII进行)
/* 这里放一个通用方法 字节小程序也可以使用 */ /* params为排序对象 , ttKey是字节小程序key ,h5Key微信h5key */ const sortStr = (params, ttKey, h5Key) => { const paramKeys = Object.keys(params).sort(); let signStr = ""; paramKeys.forEach((key) => { let value = params[key]; // 空值,risk_info, sign 不参与签名 if (!value || ["risk_info", "sign"].indexOf(key) >= 0) { return; } if (signStr.length > 0) { signStr += "&"; } if (typeof value === "object") { value = JSON.stringify(value); } signStr += key + "=" + value; }); if (ttKey) { signStr += `${ttKey}`; return signStr; } if (h5Key) { signStr += "&key=" + h5Key; return signStr; } }; export default sortStr;
(2)签名方法node版(如果不能使用 后面有js版)
const crypto = require("crypto"); const createSign = (signStr) => { const md5 = crypto.createHash("md5"); const sign = md5.update(signStr).digest("hex"); return sign; }; export default createSign;
(3)随机字符方法
/* 随机字符串32 */ function randomString() { /* 去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1 */ let chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678"; let maxPos = chars.length; let pwd = ""; for (let i = 0; i < 32; i++) { pwd += chars.charAt(Math.floor(Math.random() * maxPos)); } return pwd; } export default randomString;
4.封装支付方法 (vue可用)
// ASCII 码排序 import sortStr from "../MD5/sortStr/sortStr"; // md5 加密 // import wxMD5 from "../MD5/md5"; import nodeMd5 from "../MD5/nodeMd5"; // 32位随机串 import randomString from "../randomString/randomString"; let h5PayFn = { /* 下单 */ h5Pay(total = 100, ip = "127.0.0.1") { // ...h5obj } } export default h5PayFn;
// 微信h5支付 import h5PayFn from "./H5pay"; Vue.prototype.$utils = { ...h5PayFn, };
5.使用
/* 这里使用的是 flyio 不要忘记ip地址 */ let { h5Obj, formData } = this.$utils.h5Pay(100, this.ip); // 生成的订单号 let out = h5Obj.out_trade_no; // 下单 this.$utils.flypost("https://api.mch.weixin.qq.com/pay/unifiedorder", formData) .then((res) => { console.log(res);
// 得到最后结果 mweb_url 进行跳转即可
}).catch()
6.常见报错
https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4
1.商家存在未配置的参数,请联系商家解决
一般是因为微信后台未配置支付的域名 , 这个一定要注意 ,有的可能一个微信绑定多个商户号! ,要确保配置正确
jsMD5排序