微信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 条评论