微信jssdk踩坑 vue前端+php后端生成签名
前端Vue(VUX) ,后端PHP(TP3)
微信jssdk文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
先生成微信开发者测试号的appid 与appsecret
根据文档引入 jssdk(我前端用的是vux ui框架 使用的是他封装好了的jssdk)
因为在做前后端分离项目,所以 需要异步请求后台获取 config
前端代码如下:
let url =encodeURIComponent(window.location.href.split('#')[0]);//后台生成签名 需要前端页面的url 使用encodeUPIComponent处理并去去除#号后面的哈希
Vue.http.get('http://xxxx.cn/wechat/base/getJssdkConfig?url=' + url).then((res) => {
let wxdata = res.data;
wxdata.debug = true;
wxdata.jsApiList = [
// 所有要调用的 API 都要加到这个列表中
'onMenuShareTimeline',//分享到朋友圈
'onMenuShareAppMessage',//分享给朋友
'onMenuShareQQ',//分享到QQ
'onMenuShareQZone',//分享到QQ空间
'onMenuShareWeibo'//分享到腾讯微博
];
Vue.wechat.config(wxdata);
// console.log(wxdata);
});
Vue.wechat.ready((e) => {
console.log("okokok");
});
Vue.wechat.error(function (res) {
console.log(res);
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
后端接口代码:
<?php
namespace WeChat\Controller;
use Think\Controller;
class BaseController extends Controller
{
protected $token;
protected $ticket;
protected $url;
protected $signPackage;
public function _initialize(){
//处理跨域问题
header('Content-Type:application/json; charset=utf-8');
header('Access-Control-Allow-Origin:*');
header('Access-Control-Max-Age:86400'); // 允许访问的有效期
header('Access-Control-Allow-Headers:*');
header('Access-Control-Allow-Methods:OPTIONS, GET, POST, DELETE');
}
public function index()
{
echo "wechat";
}
private function httpGet($url)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_TIMEOUT, 500);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); //ssl不验证证书下同
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); //ssl不验证
$res = curl_exec($curl);
curl_close($curl);
return $res;
}
/**
* @param string $url
*/
public function getJssdkConfig($url = "")
{
// $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
// $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
$this->getAccessToken();//获取toekn
$this->getJsApiTicket();//获取ticket
$this->generateSignature();//生成签名
$this->ajaxReturn($this->signPackage);//返回配置给前端
}
/**
* 从微信服务器或数据库缓存中获取token
*/
protected function getAccessToken()
{
$token = M('accesstoken')->limit(1)->find();
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . C('wechat_appid') . "&secret=" . C('wechat_appsecret');
if ($token) {
$token['time'] = (int)$token['time'];
$token['expires_in'] = (int)$token['expires_in'];
//如果数据库中的token存放+过期时间 小于了当前时间 更新token
if ($token['time'] + $token['expires_in'] < time()) {
//更新
$returnData = json_decode($this->httpGet($url));
$resData['access_token'] = $returnData->access_token;
$resData['expires_in'] = (string)$returnData->expires_in;
$resData['time'] = (string)time();
M('accesstoken')->where(array('id' => $token['id']))->save($resData);
$res = $resData;
$res['source'] = "update";
} else {
//缓存
$res = $token;
$res['source'] = "cache";
}
} else {
//新增
$returnData = json_decode($this->httpGet($url));
$resData['access_token'] = $returnData->access_token;
$resData['expires_in'] = (string)$returnData->expires_in;
$resData['time'] = (string)time();
M('accesstoken')->add($resData);
$res = $resData;
$res['source'] = "new";
}
$this->token = $res;
}
/**
* 从微信服务器或数据库缓存中获取ticket
*/
protected function getJsApiTicket()
{
$ticket = M('jsticket')->limit(1)->find();
$url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . $this->token['access_token'] . '&type=jsapi';
if ($ticket) {
$ticket['time'] = (int)$ticket['time'];
$ticket['errcode'] = (int)$ticket['errcode'];
$ticket['expires_in'] = (int)$ticket['expires_in'];
if ($ticket['time'] + $ticket['expires_in'] < time()) {
//更新
$returnData = json_decode($this->httpGet($url));
$resData['ticket'] = $returnData->ticket;
$resData['errmsg'] = $returnData->errmsg;
$resData['errcode'] = $returnData->errcode;
$resData['expires_in'] = $returnData->expires_in;
$resData['time'] = time();
M('jsticket')->where(array('id' => $ticket['id']))->save($resData);
$res = $resData;
$res['source'] = "update";
} else {
//缓存
$res = $ticket;
$res['source'] = "cache";
}
} else {
//新增
$returnData = json_decode($this->httpGet($url));
$resData['ticket'] = $returnData->ticket;
$resData['errmsg'] = $returnData->errmsg;
$resData['errcode'] = $returnData->errcode;
$resData['expires_in'] = $returnData->expires_in;
$resData['time'] = time();
M('jsticket')->add($resData);
$res = $resData;
$res['source'] = "new";
}
$this->ticket = $res;
}
/**
* 生成签名数据包
*/
protected function generateSignature()
{
$noncestr = 'crazyming' . time();
$jsapi_ticket = $this->ticket['ticket'];
$timestamp = time();
$url = $this->url;
$string = "jsapi_ticket=" . $this->ticket['ticket'] . "&noncestr=$noncestr×tamp=$timestamp&url=$url";
$signature = sha1($string);
$signPackage = array(
"appId" => C('wechat_appid'),
"nonceStr" => $noncestr,
"timestamp" => $timestamp,
"url" => $url,
"signature" => $signature,
"ticket" => $jsapi_ticket,
"token" => $this->token['access_token']
);
$this->signPackage = $signPackage;
}
}
如提示invalid url domain:
当前页面所在域名与使用的appid没有绑定,请确认正确填写绑定的域名,仅支持80(http)和443(https)两个端口,因此不需要填写端口号。
例如:

如提示invalid signature 请检查:
1.确认签名算法正确,可用http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。
2.确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。
3.确认url是页面完整的url(请在当前页面alert(location.href.split('#')[0])确认),包括'http(s)://'部分,以及'?'后面的GET参数部分,但不包括'#'hash后面的部分。
4.确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。
5.确保一定缓存access_token和jsapi_ticket。
6.确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去'#'hash部分的链接(可用location.href.split('#')[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。
版权声明:
作者:东明兄
链接:https://blog.crazyming.com/note/803/
来源:CrazyMing
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论