JS交互微信之JSAPI支付

JavaScript017

JS交互微信之JSAPI支付,第1张

本篇为 JS交互微信系列篇 的第四篇 微信JSAPI支付 ,记录在微信内置浏览器内用调用微信支付过程。

JSAPI支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。

要拥有两个账号:

要开通产品中心的JSAPI支付。然后 产品中心=>开发配置=>支付配置=>公众号支付配置 绑定支付授权目录,写已通过ICP备案的域名。

另外,要在ip白名单中,配置测试地址ip和线上生产地址ip,不然各种回调都会失败!

由于在微信内支付需要获取用户的 openid ,要获取它则必须通过网页授权配置。在公微信公众平台中, 公众号设置=>功能设置=>网页授权域名 中按要求填写。

在支付流程方面,重点依然都在后端处理,前端方面步骤比较简单。本文只叙述前端内容。

在将要进入支付的前一页面,直接接入微信授权,然后跳转进要支付的那个页面。举个例子:有a、b两个页面,在b页面用到支付,b页面由a页面跳转而来。那么在a页面跳b页面的时候,别直接跳转b的url,而是跳转到:

https://open.weixin.qq.com/connect/oauth2/authorize?appid={appId}&redirect_uri={b.html}&response_type=code&scope=snsapi_base#wechat_redirect

我们注意到,这里有这两个需要自己写的参数: appid 和 redirect_uri ,意义是:

另外,还有一个注意的点是, b.html这个url我们要进行encode转码,不然地址解析可能会出现问题!

上一步执行完后,在微信浏览器中,我们会得到一个链接,类似:

b.html?&code={code}&state=#/

在此处,我们得到了一个code值,这就是我们获取 openid 的凭证了。

获取方法当然是把值传给后台,后台去处理啦~

在上一步中,我们拿到code值后,就可以提交一些信息给后端了,比如商品相关属性、总价等,另外加上code值,传给后端。后端一顿操作后,返回给前端。我们需要的参数如下(后端返回下面这些参数):

上个步骤拿到需要交互微信的参数后,就开始调用微信的支付接口了,如下:

至此,调用微信JSAPI来完成在微信内的支付就完成了。

整理一下通过h5做微信分享相关配置。

登录微信公众号, 获取AppID , 配置白名单 ,然后 配置JS接口安全域名 。

登录公众号后,左侧菜单栏选择:开发 =>基本配置,直接复制开发者ID(AppID)即可:

注意使用公网IP

左侧菜单栏选择:设置 =>公众号设置:

网页授权主要是获取微信openId使用,如果只是用分享操作,本步可以略过。

网页授权介绍

大致步骤是:

在配置完前面AppId、白名单及安全域名后,开始处理网页授权。

网页授权这一块儿内容主要是后端需要处理的内容较多,前端还是很简单的,仅需要跳入微信链接即可。为什么要走这一步呢因为有些操作,例如微信支付、播放微信录音、获取微信地址、微信卡券、商品、小店等等许多功能必须在微信浏览器汇总打开操作才可以,因此需要跳入微信浏览器及微信链接来处理后续操作。当配置后,链接便只有在微信浏览器中打开才会生效了,不然会提示:

链接如下:

https://open.weixin.qq.com/connect/oauth2/authorize?appid={$appId}&redirect_uri=={$URL}&response_type=code&scope=snsapi_base#wechat_redirect

参数分解

可见,上面需要填入的变量有二,一个是前面回去的AppId,另外一个则是url,需要写的是与配置域名所对应域名下的url,并且要进行urlEncode编码处理使用。

在拿到上述完整链接后,通过 window.location.href = ${url} 进行网页授权即可。在授权成功后,页面会重定向到自己设置的url页面去,然后在该连接上会有code值,取出即可:

将拿到的code值传给后端即可,看具体需求决定是否前端使用openId,如果非必要则不在前端获取保存或者由后端加密后传给前端使用。

大致分为五个步骤:

在步骤 1.3 中已经配置。

在需要调用JS接口的页面引入如下JS文件: https://res.wx.qq.com/open/js/jweixin-1.6.0.js

备注:支持使用 AMD/CMD 标准模块加载方法加载

配置需要如下几个参数:

那这些参数从哪儿来呢?依旧不用担心,依然是交给后端处理,后端返回时间戳、随机串及签名,其他的自己配置即可。

通过后端获取需要进行一个小交互,将此时的链接地址(window.location.href)传给后端即可。

于是就有了上述的除了最后一个以外的所有参数。最后一个 jsApiList 则是写分享接口,如我们想要分享到朋友圈、QQ、腾讯微博这3个,那就写:

可以发现,我们其实多配置了一个 checkJsApi ,这个是一个判断配置,可以判断当前客户端版本是否支持指定JS接口。

签名算法

所有JS接口列表

接下来就可以写分享信息配置了。配置信息一般都是通过 wx.ready 处理的:

例如我们要分享到朋友圈,配置则如下:

注意:不要出现 诱导分享

同样,一般都是通过 wx.error 处理失败相关信息:

其实微信分享(地理位置、扫一扫、卡券等微信各类接口)都是通过上述步骤配置的,可举一反三,在面对不同需求时通过微信开发文档来进行更为复杂的操作。

登录你的微信平台,点击“公众号设置”。

点击“功能设置”,然后点击“设置”。

设置JS接口安全域名。这里填写的是一级域名,不带www和http。最多可以设置三个域名。设置完后点击确定。(多说一句,相比以前的分享没有任何域名限制,这里设置安全域名,目的是为了当发现此公众平台发现诱导分享行为时,可以根据此域名追溯到所有分享出去的链接,以及通过这些链接增加的粉丝。这样,微信就可以牢牢控制了你的微信平台,一旦发现违规,让分享链接失效,删除掉诱导行为增加的粉丝,是瞬间就可以完成的。因此,微信平台的开发者,一定要合理来使用分享功能,不要因小失大。等到你的微信平台被封,估计哭都来不及)

在开发者中心中获取你的AppID和AppSecret,接下来在获取令牌时,需要这两个信息。

获取令牌。在服务器端完成,代码如下:

function wx_get_token() {

$token = S('access_token')

if (!$token) {

$res = file_get_contents('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.'你的AppID'.'&secret='.'你的AppSecret')

$res = json_decode($res, true)

$token = $res['access_token']

// 注意:这里需要将获取到的token缓存起来(或写到数据库中)

// 不能频繁的访问https://api.weixin.qq.com/cgi-bin/token,每日有次数限制

// 通过此接口返回的token的有效期目前为2小时。令牌失效后,JS-SDK也就不能用了。

// 因此,这里将token值缓存1小时,比2小时小。缓存失效后,再从接口获取新的token,这样

// 就可以避免token失效。

// S()是ThinkPhp的缓存函数,如果使用的是不ThinkPhp框架,可以使用你的缓存函数,或使用数据库来保存。

S('access_token', $token, 3600)

}

return $token

}

注意:返回的access_token长度至少要留够512字节。接口返回值:

{"access_token":"ACCESS_TOKEN","expires_in":7200}

{"access_token":"vdlThyTfyB0N5eMoi3n_aMFMKPuwkE0MgyGf_0h0fpzL8p_hsdUX8VGxz5oSXuq5dM69lxP9wBwN9Yzg-0kVHY33BykRC0YXZZZ-WdxEic4","expires_in":7200}

获取jsapi的ticket。jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。

function wx_get_jsapi_ticket(){

$ticket = ""

do{

$ticket = S('wx_ticket')

if (!empty($ticket)) {

break

}

$token = S('access_token')

if (empty($token)){

wx_get_token()

}

$token = S('access_token')

if (empty($token)) {

logErr("get access token error.")

break

}

$url2 = sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi",

$token)

$res = file_get_contents($url2)

$res = json_decode($res, true)

$ticket = $res['ticket']

// 注意:这里需要将获取到的ticket缓存起来(或写到数据库中)

// ticket和token一样,不能频繁的访问接口来获取,在每次获取后,我们把它保存起来。

S('wx_ticket', $ticket, 3600)

}while(0)

return $ticket

}

接口返回值:

{"errcode":0,"errmsg":"ok","ticket":"sM4AOVdWfPE4DxkXGEs8VMKv7FMCPm-I98-klC6SO3Q3AwzxqljYWtzTCxIH9hDOXZCo9cgfHI6kwbe_YWtOQg","expires_in":7200}

签名,将jsapi_ticket、noncestr、timestamp、分享的url按字母顺序连接起来,进行sha1签名。

noncestr是你设置的任意字符串。

timestamp为时间戳。

$timestamp = time()

$wxnonceStr = "任意字符串"

$wxticket = wx_get_jsapi_ticket()

$wxOri = sprintf("jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s",

$wxticket, $wxnonceStr, $timestamp,

'要分享的url(从http开始,如果有参数,包含参数)'

)

$wxSha1 = sha1($wxOri)