详解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 相关文章推荐
JavaScript Event事件学习第一章 Event介绍
Feb 07 Javascript
jquery获取input表单值的代码
Apr 19 Javascript
JavaScript高级程序设计 事件学习笔记
Sep 10 Javascript
获取服务器传来的数据 用JS去空格的正则表达式
Mar 26 Javascript
jquery div模态窗口的简单实例
May 28 Javascript
ES6生成器用法实例分析
Apr 10 Javascript
Javascript中 toFixed四舍六入方法
Aug 21 Javascript
JavaScript实现为事件句柄绑定监听函数的方法分析
Nov 14 Javascript
npm 更改默认全局路径以及国内镜像的方法
May 16 Javascript
解决Layui 表单提交数据为空的问题
Aug 15 Javascript
electron中使用bootstrap的示例代码
Nov 06 Javascript
Vue 样式绑定的实现方法
Jan 15 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
菜鸟学PHP之Smarty入门
2007/01/04 PHP
解析array splice的移除数组中指定键的值,返回一个新的数组
2013/07/02 PHP
PHP中VC6、VC9、TS、NTS版本的区别与用法详解
2013/10/26 PHP
Yii使用DeleteAll连表删除出现报错问题的解决方法
2016/07/14 PHP
[原创]PHP实现SQL语句格式化功能的方法
2017/07/28 PHP
php图片裁剪函数
2018/10/31 PHP
javascript使用prototype完成单继承
2014/12/24 Javascript
jquery实现带缩略图的全屏图片画廊效果实例
2015/06/25 Javascript
JS不用正则验证输入的字符串是否为空(包含空格)的实现代码
2016/06/14 Javascript
Node.js Streams文件读写操作详解
2016/07/04 Javascript
基于JavaScript实现在新的tab页打开url
2016/08/04 Javascript
微信小程序 自己制作小组件实例详解
2016/12/22 Javascript
Node.JS更改Windows注册表Regedit的方法小结
2017/08/18 Javascript
Three.js基础学习之场景对象
2017/09/27 Javascript
JS实现网页抢购功能(触发,终止脚本)
2017/11/27 Javascript
Vue Router的懒加载路径的解决方法
2018/06/21 Javascript
微信小程序使用swiper组件实现类3D轮播图
2018/08/29 Javascript
vue项目中,main.js,App.vue,index.html的调用方法
2018/09/20 Javascript
在vue项目中,将juery设置为全局变量的方法
2018/09/25 Javascript
vue使用el-upload上传文件及Feign服务间传递文件的方法
2019/03/15 Javascript
javascript实现函数柯里化与反柯里化过程解析
2019/10/08 Javascript
详解关闭令人抓狂的ESlint 语法检测配置方法
2019/10/28 Javascript
bootstrap-table后端分页功能完整实例
2020/06/01 Javascript
小程序实现简单语音聊天的示例代码
2020/07/24 Javascript
Python中for循环控制语句用法实例
2015/06/02 Python
Python自定义函数实现求两个数最大公约数、最小公倍数示例
2018/05/21 Python
Python读取Excel表格,并同时画折线图和柱状图的方法
2018/10/14 Python
python 自动批量打开网页的示例
2019/02/21 Python
Python3实现的旋转矩阵图像算法示例
2019/04/03 Python
在Python中通过threshold创建mask方式
2020/02/19 Python
基于Python组装jmx并调用JMeter实现压力测试
2020/11/03 Python
美国巧克力喷泉品牌:Sephra
2019/05/05 全球购物
美国波西米亚风格精品店:South Moon Under
2019/10/26 全球购物
什么是数据库锁?Oracle中都有哪些类型的锁?
2015/08/21 面试题
单位员工收入证明样本
2014/10/09 职场文书
优秀党员个人总结
2015/02/14 职场文书