基于Vue微信公众号JS SDK实现

基于Vue微信公众号JS SDK实现

的每个步骤,然后我的demo是基于vue的一个小项目,后台是php的Slim框架。由于官方文档写得太全以至于开发时候看得懵逼,这篇文章我就尽量少说,只记录重要步骤。

(其实v不vue没多大关系。。只是比较吸引流量罢了哈哈。。)

至于公众号配置,网页授权回调域名的配置这里就忽略了。

然后在后面会分两部分,先说网页授权的实现用来获取用户信息,然后再说实现在Vue上使用JS SDK和PHP的整合。两部分的中间联系就是前部分获取到的access_token,后部分需要用到。

第一步:实现用户授权页面,获取code

第一步的目的就是为了获取到code,至于code有什么用后面再说。

授权流程图

如上图是一个简单的授权流程图,对于用户来说入口action是我们的应用首页,主要作用就是跳转到原谅色的授权页,而实际应用则是在授权请求的时候带上的redirect_uri
下面放码:
服务端:

1
2
3
4
5
6
7
8
9
10



$app->get('/',function($req,$res,$args){

$url = urlencode('http://your.url/app');//这是我要跳转的目的地,需要进行url编码

return $res->withStatus(302)->withHeader('Location', "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APP_ID&redirect_uri=$url&response_type=code&scope=snsapi_userinfo&state=done#wechat_redirect");

});

其中需要改动的就是APP_ID和需要跳转的redirect_uri;
然后就可以用微信开发者工具来测试下了:
授权页面

【诶?官方工具的适配都。。】确认授权以后就可以跳转到我们设置的redirect_uri的页面去了。

第二步:通过code来换取网页授权access_token

code其实相当于一个排队的筹,真正敲开相关接口的大门的是access_token。因此在应用页action里面我们就要先通过code换取access_token。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66



$app->get('/app',function($req,$res,$args){

//1.判断token是否过期了

if ( time() > $_SESSION['expires_time'] ){

//2.获取access_token

$code = $req->getParam('code');

$tokendata = getToken($code);

//3.保存在session中

$_SESSION['access_token'] = $tokendata['access_token'];

$_SESSION['expires_time'] = $tokendata['expires_in'] + time();

$_SESSION['openid'] = $tokendata['openid'];

}

//4.获取用户信息

$userdata = getUserInfo();

if (isset($userdata['openid'])){

//保存或更新用户信息

saveUser($userdata);

}

return$this->renderer->render($res, 'index.html', $args);

});

//获取token

functiongetToken($code){

$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APP_ID&secret=APP_SECRET&code=$code&grant_type=authorization_code";

return json_decode(get($url),true);

}

//获取用户信息

functiongetUserInfo(){

//get userdata

$token = $_SESSION['access_token'];

$openid = $_SESSION['openid'];

$url = "https://api.weixin.qq.com/sns/userinfo?access_token=$token&openid=$openid&lang=zh_CH";

return json_decode(get($url),true);

}

因为频繁地请求access_token会被微信方拒绝,所以要保存access_token,保存的时候要注意,敏感信息必须保存在服务端上。
为了避免频繁请求access_token,就要把当前的超时时间expires_in + time()记录下来,作为下次进入页面时候的检查项(一般是7200秒)。然后微信还提供了一个refresh_token用来当access_token过期的时候刷新它的,refresh_token的过期时间是30天,但是我还没做过过了30天还有用户想要用的应用。。所以这里就忽略refresh_token机制了,对于access_token来说,每个用户两个小时请求一次应该也不算频繁了(当然,讲的是用户量适量的情景)。

再然后就是获取用户的信息了,没什么好说的,就这样吧。

第一步:服务端生成前端需要注入的配置信息

这部分想要了解每个地方的含义的就去看文档吧,这里直接丢代码直接用了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106



//生成使用微信JS-SDK需要注入的配置信息,参数$url(当前网址的url)

function getConfig($url){

$array = [];

$array['debug'] = true;

$array['appId'] = APP_ID; //记得换APP_ID

//生成签名的时间戳

$time = time();

$array['timestamp'] = $time;

//签名使用的随机字符串

$nonceStr = nonceStr();

$array['nonceStr'] = $nonceStr;

$array['signature'] = signature($time,$url,$nonceStr);

//设置需要使用的js接口

$array['jsApiList'] = ['checkJsApi','onMenuShareTimeline',

'onMenuShareAppMessage',

'chooseImage']; //这里的接口参照文章

//返回配置信息

return json_encode($array);

}

//生成签名函数,参数$time(生成签名的时间),$url(网页的url),$nonceStr(随机字符串)

//因为我们注入网页的配置信息中,生成签名的时间和随机字符串必须和注入的一样,

//所以我生成签名的时候传递一个参数,以达到相同的时间戳,和随机字符串。

function signature($time,$url,$nonceStr){

//拼接字符串

$string = 'jsapi_ticket='.getJsApiTicket().'&noncestr='.$nonceStr.'&timestamp='.$time.'&url='.$url;

//生成签名

$string = sha1($string);

return $string;

}

//生成随机字符串

function nonceStr(){

//定义一个字符串

$chars='ABCDFFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';

//当前的时间戳

$time = time();

//从该字符串中获取随机字符串

$chars = $chars.$time;

//打乱字符串

$chars = str_shuffle($chars);

return substr($chars,0,16);

}

//获取JSapi ticket

function getJsApiTicket(){

if ( time() > $_SESSION['ticket_expires_time'] ){

$access_token = $_SESSION['access_token'];

$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$access_token&type=jsapi";

$ticketData = json_decode(get($url),ture);

$_SESSION['ticket_expires_time'] = time() + $ticketData['expires_in'];

$_SESSION['js_ticket'] = $ticketData['ticket'];

}

return $_SESSION['js_ticket'];

}

然后准备一个action用来返回config json就行

1
2
3
4
5
6
7
8



$app->get('/config',function($req,$res,$args){

return getConfig('http://your.url');

});

第二步:前端引入wechat-js-sdk库

直接一句命令:

1
2
3
4



npm install -S weixin-js-sdk

然后在要使用的*.vue页面中引入

1
2
3
4



import wx from'wexin-js-sdk'

第二步:前端Vue请求注入配置信息

先说下框架是Vue.js,然后请求库用的是axios。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78



...

created(){

//获取配置

var url = 'http://your.url/config'

var _this = this;

//请求注入配置

axios.post(url, {})

.then(response => {

var data = response.data;

//注入到wx

wx.config({

appId: data.wechat_appid,

// debug: true,

timestamp: data.timestamp,

nonceStr: data.nonceStr,

signature: data.signature,

jsApiList: data.jsApiList

});

wx.ready(function(){

//配置分享接口

var shareData = {

title: 'title',

link:'http://your.link',

imgUrl:'',

success:function(){

},

cancel:function(){

}

}

wx.onMenuShareTimeline(sdata);

wx.onMenuShareAppMessage(sdata);

});

})

.catch(e => {

console.log(e);

})

},

...

到此整个旅途都完成了,具体代码都是可以开箱即用。

附录

Post和Get curl的封装方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114



/**

* @param $url

* @param array $post_data

*

* @return string

*/

functionpost($url,$post_data = array()){

try {

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

// post数据

curl_setopt($ch, CURLOPT_POST, 1);

// post的变量

curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));

$output = curl_exec($ch);

$curl_errno = curl_errno($ch);

curl_close($ch);

if ($curl_errno > 0) {

return json_encode(array(

'ResultCode' => 0,

'Msg' => 'Curl error: error code ('.$curl_errno.')'

));

}

return $output;

}catch(Exception $e){

print'Error:'.$e->getMessage();

exit();

}

}

/**

* @param $url

*

* @return string

*/

functionget($url){

try {

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

curl_setopt($ch, CURLOPT_HEADER, 0);

$output = curl_exec($ch);

$curl_errno = curl_errno($ch);

curl_close($ch);

if ($curl_errno > 0) {

return json_encode(array(

'ResultCode' => 0,

'Msg' => 'Curl error: error code ('.$curl_errno.')'

));

}

return $output;

}catch(Exception $e){

print $e->getMessage();

exit();

}

}