ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 前言 完成微信h5支付的你,继续公众号的支付也许更简单哦。 ## 场景 微信浏览器中的应用支付必须依赖于公众号支付,下面就公众号支付中的一些技术点进行详细的解析。 ## 准备工作 ### 基本配置申请 参考资料:[微信公众号开通支付功能--百度经验教程](https://jingyan.baidu.com/article/636f38bb48c6fcd6b9461071.html) ### 基本信息 * 服务号,服务号绑定的管理员号 * 开通支付账号,并记住支付账号,与支付账号绑定的微信号 * 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参考文档](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN) #### 二 根据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。(比较麻烦,不推荐使用) 参考文档: ## 参考文档 * [设置支付目录以及回调域名](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3) ## 其他 - [微信支付java指南](https://mp.weixin.qq.com/s/VQJivfo3_rUMoqgAsj-_uQ)