原文:https://blog.niceue.com/front-end-development/wechat-h5-payment-process-as-well-as-some-pits.htmljavascript
最近作的 SPA 网站集成了微信支付,使用的是微信 H5 调起支付API接口。作完后对微信 H5 支付的流程有了进一步的了解,在先后端调试接口的过程当中也遇到了一些问题,在这里记录下来。php
wx.chooseWXPay
发起支付wx.chooseWXPay({ timestamp: '', // 支付签名时间戳 nonceStr: '', // 支付签名随机串 package: '', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***) signType: 'MD5', // 签名方式 paySign: '', // 支付签名 })
这里看起来是 5 步,但其实还少了一步。调用“统一下单”接口的时候须要微信用户的 openid。html
官方解释前端
加密后的微信号,每一个用户对每一个公众号的 openid 是惟一的。对于不一样公众号,同一用户的 openid 不一样
这个 openid 只能在微信环境经过重定向拿到。可是在下单的时候用的是 ajax 请求,还用重定向用户体验就比较差。因此须要在进入微信的时候就经过重定向拿到 openid 缓存起来,后面就能够直接使用了。因此入口页面就要作点小动做。java
官方有OpenID的获取指引。对于 H5 应用,获取方式分 3 步走:ajax
后端能够定义一个 /wechat/redirect
接口,例如:后端
http://yoursite.com/wechat/redirect?url=home_url
用这个地址重定向获取 code 地址,其中的 url 参数为最终的重定向地址,在拿到 openid 后跳转到该 urlapi
接口地址缓存
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirec
接口参数:服务器
appid
: 公众帐号IDredirect_uri
: 接收 code 的回调地址(请UrlEncode)response_type
: 固定值 codescope
: 应用受权做用域,填 snsapi_base 或者 snsapi_login(可获取用户信息,如头像、昵称等)state
: 用于保持请求和回调的状态,防止 csrf 攻击,可设置为简单的随机数加 session 进行校验提示:snsapi_login 会跳转到受权页让用户受权
微信接着会重定向三次,第三次重定向返回到 redirect_uri 地址,而且带上了 code 参数
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
获取到 openid 后注意在 session 中缓存起来
在OpenID的获取指引文档,请注意黑色标题“微信公众平台”和“微信开放平台”。两个地方获取 code 的接口地址不同,但参数是同样的。最开始后端看错了文档使用的是“网站应用微信登陆”文档里面提供的获取 code 的接口,这样子怎么都是调不通的。
// 微信公众平台是 https://open.weixin.qq.com/connect/oauth2/authorize // 微信开放平台是 https://open.weixin.qq.com/connect/qrconnect
timeStamp
,而前端调用支付接口使用全小写 timestamp
微信官方网页端调起支付API这个接口文档参数却误导观众,写的是驼峰的 timeStamp
后端为了方便返回给前端的也是 timeStamp,因此在前端须要转换
解决办法:
if (!data.timestamp) data.timestamp = data.timeStamp
http://yousite.com/mobile/#!/checkout
以上路径,iOS 微信识别正确:http://yousite.com/mobile/
而 Android 微信识别出的目录是:http://yousite.com/mobile/#!/checkout
这应该是 Android 版微信的 Bug
解决办法是在 #
前添加一个 ?
:http://yousite.com/mobile/?#!/checkout