支付类型很多,这里是指在公众号上调用 JSAPI支付
开通支付
这部分比较繁琐,但都是一些资料认证,在公众号平台的入口进入申请提交就可以了。
商户平台
如果成功开通了 微信支付
,那么你就可以登录 商户平台 了,进行关联公众号,成功关联之后,就能实现在当前公众号中使用微信支付收款。
在 产品中心 > APPID授权管理 > 账号关联(AppID绑定) > 已关联账号
,可以看到 是否已经关联公众号(服务号) 。
准备开发所需参数
商户平台 > 产品中心 > 开发配置
处,可以找到商户号
。商户平台 > 账户中心 > API安全 > API密钥
安装安全证书之后,就可以设置API密钥,密钥为32为字符,自己定义。商户平台 > 账户中心 > API安全 > API证书
,申请证书,下载的是一个zip压缩包,有p12和pem证书。公众平台 > 开发 > 基本配置 > AppId
公众平台 > 开发 > 基本配置 > AppSecret
公众号设置
公众号设置 > 功能设置
,在 业务域名,JS接口安全域名,网页授权域名
三个地方设置前端的域名,如 wx.mydomain.com
公众平台-后端开发
第一步先把公众平台的接口调通,这相对简单一些,在保证公众平台没问题的情况下,再进行微信支付的接口开发。
1. 签名接口
首先,后端要提供一个签名接口,用于前端签名当前的URL,否则无法调用 JSSDK
的接口。
签名算法可以看 微信文档 ,大概流程:前端将URL发到后端,后端签名成功返回 timestamp、nonceStr、signature
三个参数的结果。
2. 获取用户的OpenId
OpenId
是用户的标识,在支付的时候要用到。本身这个接口非常简单,前端也可以直接向微信服务器请求,但为了不暴露公众号的 AppSecret
参数和跨域问题,这个请求放在后端发起。
1 | https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code |
前端传入code,后端发起GET请求,响应结果直接返给前端。
公众平台-前端开发
前端开发在 《微信web开发者工具》(以下称:模拟器)下进行,下载地址:下载 。需要在 公众号平台 > 开发者工具 >web开发者工具
绑定开发者的微信号。
坑:npm上没有微信官方发布的包,
weixin-jsapi
是个人发布v1.1.0 版本的包。网上很多文章用
weixin-js-sdk
这个包也是个人发布的,目前最新的1.4.0版,但是只能通过require使用,Vue中并不能用,有问题。
1. 微信网页授权
微信文档:第一步 拿到 code
直接向后端发起请求获取 OpenId
,正确的话,有以下数据包返回,我们就用到openid
,缓存起来备用 。
1 | { |
2. 通过config接口注入权限验证配置
所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用。
1 | wx.config({ |
上面这些参数,需要向后端的 签名接口
发起请求获取,appId
可以写在前端代码中,也可以由后端响应返回。
1 | jsApiList: ['getNetworkType','chooseWXPay'] |
这里是两个需要使用的JS接口,getNetworkType
用于测试,chooseWXPay
就是微信支付的接口。
执行 wx.config
,如果模拟器弹出 ok
的话,表示签名没问题了。
由于微信支付在模拟器无法调试,所以有必要选用一个其他接口(如 getNetworkType)来调试。
3. 检查能否调用JSSDK
1 | wx.getNetworkType({ |
如果模拟器弹出当前的网络类型,就表示成功了。
沙箱sandbox测试开发
微信支付沙箱开发时, 官方开发文档只是简单说明, 并没有给出相关示例。
沙箱开发要修改两个地方:
- 路径
- 秘钥Key
其中,Key要通过Post请求获取,但文档请求参数怎么传说的不清楚(其实是xml格式), 文档地址 。
沙箱测试要关注公众号 WXPayAssist
,里面很多相关的资料,沙箱测试付款
也是要在这个公众号下进行。
获取Key的请求如下:
其中,sign 和支付的签名算法一样,要用到正式的KEY来签名。
微信支付-后端开发
微信支付的后端开发,即要调用 微信文档:统一下单 接口,获取 预支付交易会话标识 prepay_id
,生成 支付签名
响应给前端。支付签名 由:appId, timeStamp, nonceStr, package, signType
参与签名,其中
1 | String packages = "prepay_id=" + prepay_id; |
这里的签名算法直接调用微信的 JavaSDK 里面的方法,所以不管它了,要注意的是签名的类型最好统一一种,比如全部用MD5
或者HMAC-SHA256
。
1. 统一下单
调用微信的统一下单接口,所需要的参数如下:
1 | data.put("body", "腾讯充值中心-QQ会员充值");//商家名称-销售商品类目 |
微信响应结果是XML数据,转为JSON结果如下:
1 | {"nonce_str":"xxx","appid":"xxx","sign":"xxx","trade_type":"JSAPI","return_msg":"OK","result_code":"SUCCESS","mch_id":"xxx","return_code":"SUCCESS","prepay_id":"xxx"} |
解析数据包,提取 prepay_id
打包参与支付签名
的数据 (注意 timeStamp
自动一定要大写 S
)
1 | String packages = "prepay_id=" + prepay_id; |
将 支付签名
结果 sign
和 参与签名
的数据 打包响应给前端
1 | Map<String,String> result = new HashMap<>(); |
例如:
1 | {"timeStamp":"1555476146","packageStr":"prepay_id=xxx","paySign":"xx","appId":"xxx","signType":"HMAC-SHA256","nonceStr":"xxx"} |
2. 接收通知
notify_url
填的是后端的接口地址,新建一个接口用于异步接收微信支付结果。
微信服务器将以 流
的方式给这个地址发送xml格式的数据:
1 | <xml> |
接收到消息之后,要回复响应数据:
1 | <xml> |
接收数据示例代码:
要从HttpServletRequest 的 getInputStream 方法获取流,从流读取byte ,不过我们用SpringMVC可以很简洁的接收:
1 | public String notifyPay(byte[] body){ |
微信支付-前端
剩下最后一步了:唤起微信支付,这个操作要在手机微信上进行,真实的环境。
将付款的页面URL放在 商户平台 > 产品中心 >支付配置 > JSAPI支付授权目录
中,
仅有公众号支付和扫码支付需配置支付域名,APP支付、刷卡支付无需配置域名
所有使用JS API方式发起支付请求的链接地址,都必须在当前页面所配置的支付授权目录之下。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid
当公众平台接到扫码支付请求时,会回调当前页面所配置的支付回调链接传递订单信息
授权目录须以左斜杠 “/” 结尾 ,例如:
支付的地址是:http://wx.mydomain.com/#/car/pay
;
授权目录设置为:http://wx.mydomain.com/#/car/
。
1 | wx.chooseWXPay({ |
chooseWXPay
的参数都在后端的统一下单
接口响应里面,解析JSON数据即可。要注意的是,这里有一个坑 timestamp
,后端生成 支付签名
的是 timeStamp
,S
是大写的,但前端 chooseWXPay
的 timestamp
依然是全部小写的。
如果没问题,即可以看到手机的 微信支付输入密码
弹框了。