微信公众号支付前端指南
前言
完成微信h5支付的你,继续公众号的支付也许更简单哦。
场景
微信浏览器中的应用支付必须依赖于公众号支付,下面就公众号支付中的一些技术点进行详细的解析。
准备工作
基本配置申请
参考资料:微信公众号开通支付功能--百度经验教程
基本信息
- 服务号,服务号绑定的管理员号
- 开通支付账号,并记住支付账号,与支付账号绑定的微信号
- appid,秘钥
- 支付账号开通支付目录(直接支付地址的上一级目录)
- 设置了页面授权域名,并且是你的站点域名地址
- 基本接口权限,尤其是jssdk部分权限,保证尽可能都开通
业务流程图解以及时序图
与微信h5基本相同,唯一不同的是这次微信返回的需要唤起微信sdk支付的参数列表。
技术问题
获取openid
网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。获取openid分为两步,获取code,然后根据code获取openid,建议这两部分请求由后端发起,前端直接请求会涉及到跨域问题。后端直接把这两个方法定义为工具方法,使用方便,便于其他场景的复用。
一 :请求获取code,如果不想浪费时间请直接复制粘贴使用
标准格式拼接代码:
let encodeUrl=encodeURIComponent(`http://xxx/xhxwxpay?productId=${productId}&orderNo=${orderNo}`) let tempUrl=`https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx6f5de09c8ef178a7&redirect_uri=${encodeUrl}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`
请求参数说明
参数 是否必须 说明 appid 是 应用唯一标识 redirect_uri 是 请使用urlEncode对链接进行处理 response_type 是 填code scope 是 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可,这里用的 snsapi_userinfo state 否 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验 - 返回说明:
用户允许授权后,将会重定向到redirect_uri的网址上,并且带上code和state参数redirect_uri?code=CODE&state=STATE
若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数redirect_uri?state=STATE
- 参考文档:微信中web网站获取code参考文档
二 根据code获取openid
一个用户针对一个公众号openid是固定的,所以获取到一样的不用怀疑,涉及到部分敏感的公众号的秘钥等,建议是后端处理发起请求,这样也可以避免前端跨域的问题。
//网关或者后端的设置(以koa框架的为例) *post_getOpenId(){ let reqData = this.request.body; let param = { appid:'wxxxx', secret:'affsdcsdvdsvfv6', code:reqData.code, grant_type:'authorization_code' } let result = yield this.api.getOpenId(param); this.body = result; } // 获取openid 传入对象的形式,改造通用的api方法 getOpenId: function* (apiParam, json = true) { // 获取token的地址 let apiUrl='https://api.weixin.qq.com/sns/oauth2/access_token' let response = yield request.get(apiUrl, { qs: apiParam, json: json }); return responseHandle(response, apiUrl, apiParam); }.bind(this), //前端的写法,好处是避免暴露公众号的相关信息 this.$api.post("order/getOpenId", { code: this.code }).then(res => { // 正确获取openid的情况下 请求后台参数得到对应的返回参数,目前只需要openid if (res.openid) { this.openId = res.openid; //准备条件足够的话 可以唤起支付 this.topay() }else { //请求失败或者没有对应的字段 }
请求参数说明,通过code获取access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
参数 是否必须 说明 appid 是 应用唯一标识,在微信开放平台提交应用审核通过后获得 secret 是 应用密钥AppSecret,在微信开放平台提交应用审核通过后获得 code 是 填写第一步获取的code参数 grant_type 是 填authorization_code 返回结果说明
//正确的返回 { "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE", "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" } //错误的返回 {"errcode":40029,"errmsg":"invalid code"}
- 刷新fresh-token有效期
如果token失效了,可以用refresh_token重新获取一个。
微信支付sdk
方式一 :官网的方式
invoke方法 ,简单有效,直接根据接口返回参数唤起。以下代码实例是vue环境下的,其他环境请自行匹配,仅供参考。
// 准备好微信sdk部分 jsSdk(){ // 判断微信的WeixinJSBridge if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', this.onBridgeReady, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', this.onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', this.onBridgeReady); } }else{ this.onBridgeReady(); } }, // 支付sdk准备完成 onBridgeReady() { // 触发微信支付 WeixinJSBridge.invoke( 'getBrandWCPayRequest', { appId: this.payOption.appId, //公众号名称,由商户传入 timeStamp: this.payOption.timeStamp, //时间戳,自1970年以来的秒数 nonceStr: this.payOption.nonceStr, //随机串 package: this.payOption.package, //prepay_id用等式的格式 signType: this.payOption.signType, //微信签名方式: paySign: this.payOption.paySign, //微信签名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { // 支付成功 返回成功页 let tempUrl="//paysucc" location.href=tempUr } else{ // 取消支付或者其他情况 get_brand_wcpay_request:cancel get_brand_wcpay_request:fail let tempUrl='//topay' location.href=tempUrl } } ); },
方式二 : 需要引入js-weixin的模块,流程如下:
引入模块--ready--获取access-token--获取ticket--生成签名(wx.config需要)--结合接口返回参数--唤起wxpay。(比较麻烦,不推荐使用)
参考文档: