详解vue开发中调用微信jssdk的问题


Posted in Javascript onApril 16, 2019

起因

微信分享网址时无法分享图片,这个问题需要用jssdk去解决。其实开始的时候时可以看到图片的,但后来微信禁止了。所以只能使用jssdk去解决。
普通网页开发很简单,但是使用vue或其他前端框架开发spa单页面webapp的时候就会有问题了。只要url发生变化就会报签名错误。其实微信官方上已经写了说明。

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。
但这些说明然并卵(然而并没有什么卵用)。

问题根源

1 同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用
如果你的链接时采用hash方式,锚点变了也要重新调用,因为url发生了变化,这一点可以放在router的监听事件中比如watch一下$route,或者使用2.2 中引入的 beforeRouteUpdate 守卫。

2 生成签名时url中不能包含锚点
微信jssdk的签名是需要服务端来生成的,所以我们需要将当前页面的网址传递给服务端,由服务端生成wx.config初始化所需要的参数。
但是url传递的时候需要注意,一定一定一定不能带有锚点链接。可以使用location.href.split(‘#')[0]获取url中锚点之前的部分。
比如你的网址是http://domain.com/index.html#/food/1
你只需要把http://domain.com/index.html传递到服务端,让服务端生成签名就可以了,你在调用jssdk的时候可以把url后面添加锚点链接。

实例

安装jssdk

npm install weixin-js-sdk --save

 前段代码

export default {
  mounted() {
   this.$nextTick(function () {
    this.getConfig()
   })
  },
  data () {
   return {
    detail: [],
   }
  },
  methods: {   
   // 微信分参数
   getConfig() { 
    let url = location.href.split('#')[0] //获取锚点之前的链接
    this.$http.get('/index.php',{
     params: {
      url: url
     }
    }).then(response => {
      let res = response.data;
      this.wxInit(res);
     })
   },
   // 微信分享
   wxInit(res) {
    let url = location.href.split('#')[0] //获取锚点之前的链接 
    let links = url+'#/Food/' + this.$route.params.id;
    let title = this.detail.name + '-嘌呤查';
    let desc = '了解更多知识,请关注“嘌呤查”公众号';
    let imgUrl = this.thumb;
    wx.config({
     debug: false,
     appId: res.appId,
     timestamp: res.timestamp,
     nonceStr: res.nonceStr,
     signature: res.signature,
     jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone']
    });
    wx.ready(function() {
     wx.onMenuShareTimeline({
      title: title, // 分享标题
      desc: desc, // 分享描述
      link: links, // 分享链接
      imgUrl: imgUrl, // 分享图标
      success: function() {
//        alert("分享到朋友圈成功")
       //Toast({
        //message: "成功分享到朋友圈"
       //});
      },
      cancel: function() {
//        alert("分享失败,您取消了分享!")
       //Toast({
        //message: "分享失败,您取消了分享!"
       //});
      }
     });
     //微信分享菜单测试
     wx.onMenuShareAppMessage({
      title: title, // 分享标题
      desc: desc, // 分享描述
      link: links, // 分享链接
      imgUrl: imgUrl, // 分享图标
      success: function() {
       // alert("成功分享给朋友")
//       Toast({
//        message: "成功分享给朋友"
//       });
      },
      cancel: function() {
       // alert("分享失败,您取消了分享!")
//       Toast({
//        message: "分享失败,您取消了分享!"
//       });
      }
     });

     wx.onMenuShareQQ({
      title: title, // 分享标题
      desc: desc, // 分享描述
      link: links, // 分享链接
      imgUrl: imgUrl, // 分享图标
      success: function() {
       // alert("成功分享给QQ")
//       Toast({
//        message: "成功分享到QQ"
//       });
      },
      cancel: function() {
       // alert("分享失败,您取消了分享!")
//       Toast({
//        message: "分享失败,您取消了分享!"
//       });
      }
     });
     wx.onMenuShareWeibo({
      title: title, // 分享标题
      desc: desc, // 分享描述
      link: links, // 分享链接
      imgUrl: imgUrl, // 分享图标
      success: function() {
       // alert("成功分享给朋友")
//       Toast({
//        message: "成功分享到腾讯微博"
//       });
      },
      cancel: function() {
       // alert("分享失败,您取消了分享!")
//       Toast({
//        message: "分享失败,您取消了分享!"
//       });
      }
     });
     wx.onMenuShareQZone({
      title: title, // 分享标题
      desc: desc, // 分享描述
      link: links, // 分享链接
      imgUrl: imgUrl, // 分享图标
      success: function() {
       // alert("成功分享给朋友")
//       Toast({
//        message: "成功分享到QQ空间"
//       });
      },
      cancel: function() {
       // alert("分享失败,您取消了分享!")
//       Toast({
//        message: "分享失败,您取消了分享!"
//       });
      }
     });

    });
    wx.error(function(err) {
     alert(JSON.stringify(err))
    });
   }
  }
 }

index.php页面代码

// 官方实例,生成wx.config需要的配置信息
class JSSDK {
 private $appId;
 private $appSecret;

 public function __construct($appId, $appSecret) {
  $this->appId = $appId;
  $this->appSecret = $appSecret;
 }

 public function getSignPackage() {
  $jsapiTicket = $this->getJsApiTicket();

  // 注意 URL 一定要动态获取,不能 hardcode.
  $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
  // 注意这里是重点
  $url = !empty($_GET['url']) ? $_GET['url'] : "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";

  $timestamp = time();
  $nonceStr = $this->createNonceStr();

  // 这里参数的顺序要按照 key 值 ASCII 码升序排序
  $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url";

  $signature = sha1($string);

  $signPackage = array(
   "appId"   => $this->appId,
   "nonceStr" => $nonceStr,
   "timestamp" => $timestamp,
   "url"    => $url,
   "signature" => $signature,
   "rawString" => $string
  );
  return $signPackage; 
 }

 private function createNonceStr($length = 16) {
  $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  $str = "";
  for ($i = 0; $i < $length; $i++) {
   $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  }
  return $str;
 }

 private function getJsApiTicket() {
  // jsapi_ticket 应该全局存储与更新,以下代码以写入到文件中做示例
  $data = json_decode($this->get_php_file("jsapi_ticket.php"));
  if ($data->expire_time < time()) {
   $accessToken = $this->getAccessToken();
   // 如果是企业号用以下 URL 获取 ticket
   // $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=$accessToken";
   $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
   $res = json_decode($this->httpGet($url));
   $ticket = $res->ticket;
   if ($ticket) {
    $data->expire_time = time() + 7000;
    $data->jsapi_ticket = $ticket;
    $this->set_php_file("jsapi_ticket.php", json_encode($data));
   }
  } else {
   $ticket = $data->jsapi_ticket;
  }

  return $ticket;
 }

 private function getAccessToken() {
  // access_token 应该全局存储与更新,以下代码以写入到文件中做示例
  $data = json_decode($this->get_php_file("access_token.php"));
  if ($data->expire_time < time()) {
   // 如果是企业号用以下URL获取access_token
   // $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$this->appId&corpsecret=$this->appSecret";
   $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$this->appId&secret=$this->appSecret";
   $res = json_decode($this->httpGet($url));
   $access_token = $res->access_token;
   if ($access_token) {
    $data->expire_time = time() + 7000;
    $data->access_token = $access_token;
    $this->set_php_file("access_token.php", json_encode($data));
   }
  } else {
   $access_token = $data->access_token;
  }
  return $access_token;
 }

 private function httpGet($url) {
  $curl = curl_init();
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_TIMEOUT, 500);
  // 为保证第三方服务器与微信服务器之间数据传输的安全性,所有微信接口采用https方式调用,必须使用下面2行代码打开ssl安全校验。
  // 如果在部署过程中代码在此处验证失败,请到 http://curl.haxx.se/ca/cacert.pem 下载新的证书判别文件。
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
  curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, true);
  curl_setopt($curl, CURLOPT_URL, $url);

  $res = curl_exec($curl);
  curl_close($curl);

  return $res;
 }

 private function get_php_file($filename) {
  return trim(substr(file_get_contents($filename), 15));
 }
 private function set_php_file($filename, $content) {
  $fp = fopen($filename, "w");
  fwrite($fp, "<?php exit();?>" . $content);
  fclose($fp);
 }
}



// 逻辑代码
$appId = '你的appid';
$appSecret = '你的appSecret';
$jssdk = new JSSDK($appId, $appSecret);
$signPackage = $jssdk->GetSignPackage();
echo json_encode($signPackage);

看到上面的类中使用$_GET[‘url']接收前段传过来的数据

以上所述是小编给大家介绍的vue开发中调用微信jssdk的问题详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jquery怎样实现ajax联动框(二)
Mar 08 Javascript
以JavaScript来实现WordPress中的二级导航菜单的方法
Dec 14 Javascript
使用ajaxfileupload.js实现上传文件功能
Aug 13 Javascript
JS基于递归算法实现1,2,3,4,5,6,7,8,9倒序放入数组中的方法
Jan 03 Javascript
详解js前端代码异常监控
Jan 11 Javascript
AngularJS前端页面操作之用户修改密码功能示例
Mar 27 Javascript
jQuery用户头像裁剪插件cropbox.js使用详解
Jun 07 jQuery
Cpage.js给组件绑定事件的实现代码
Aug 31 Javascript
echarts学习笔记之图表自适应问题详解
Nov 22 Javascript
Vue使用富文本编辑器Vue-Quill-Editor(含图片自定义上传服务、清除复制粘贴样式等)
May 15 Javascript
vant 时间选择器--开始时间和结束时间实例
Nov 04 Javascript
在 HTML 页面中使用 React的场景分析
Jan 18 Javascript
怎样使你的 JavaScript 代码简单易读(推荐)
Apr 16 #Javascript
vue微信分享的实现(在当前页面分享其他页面)
Apr 16 #Javascript
在Vue项目中使用snapshot测试的具体使用
Apr 16 #Javascript
vue.js中使用echarts实现数据动态刷新功能
Apr 16 #Javascript
详解vue-cli 脚手架 安装
Apr 16 #Javascript
详解jquery和vue对比
Apr 16 #jQuery
JS使用百度地图API自动获取地址和经纬度操作示例
Apr 16 #Javascript
You might like
Syphon 虹吸式咖啡壶冲煮–拨动法
2021/03/03 冲泡冲煮
用PHP程序实现支持页面后退的两种方法
2008/06/30 PHP
深入PHP变量存储的详解
2013/06/13 PHP
async和DOM Script文件加载比较
2014/07/20 PHP
从零开始学YII2框架(五)快速生成代码工具 Gii 的使用
2014/08/20 PHP
thinkPHP5.0框架简单配置作用域的方法
2017/03/17 PHP
浅谈PHP之ThinkPHP框架使用详解
2020/07/21 PHP
Dom加载让图片加载完再执行的脚本代码
2008/05/15 Javascript
jQuery 扩展对input的一些操作方法
2009/10/30 Javascript
深入了解javascript中的prototype与继承
2013/04/14 Javascript
Jquery实现的tab效果可以指定默认显示第几页
2013/10/16 Javascript
判断js中各种数据的类型方法之typeof与0bject.prototype.toString讲解
2013/11/07 Javascript
页面加载完成后再执行JS的jquery写法以及区别说明
2014/02/22 Javascript
Jquery 实现grid绑定模板
2015/01/28 Javascript
JS模式之简单的订阅者和发布者模式完整实例
2015/06/30 Javascript
全面解析Bootstrap表单使用方法(表单按钮)
2015/11/24 Javascript
jquery Banner轮播选项卡
2016/12/26 Javascript
Node.js创建Web、TCP服务器
2017/12/05 Javascript
详解使用jQuery.i18n.properties实现js国际化
2018/05/04 jQuery
layer弹出层父子页面事件相互调用方法
2018/08/17 Javascript
详解关于element级联选择器数据回显问题
2019/02/20 Javascript
零基础写python爬虫之打包生成exe文件
2014/11/06 Python
python实现多线程抓取知乎用户
2016/12/12 Python
python中requests和https使用简单示例
2018/01/18 Python
python3安装pip3(install pip3 for python 3.x)
2018/04/03 Python
使用Template格式化Python字符串的方法
2019/01/22 Python
解决Python命令行下退格,删除,方向键乱码(亲测有效)
2020/01/16 Python
在python中实现求输出1-3+5-7+9-......101的和
2020/04/02 Python
详解Python 中的容器 collections
2020/08/17 Python
解决Python安装cryptography报错问题
2020/09/03 Python
Java里面如何创建一个内部类的实例
2015/01/19 面试题
老师推荐信
2013/10/28 职场文书
二年级数学教学反思
2014/01/21 职场文书
QQ空间主人寄语大全
2014/04/12 职场文书
影视广告专业求职信
2014/09/02 职场文书
2016年班主任培训心得体会
2016/01/07 职场文书