JSSDK实现自定义分享标题和图片

准备工作

  • 已认证的公众号(一定要认证过的!)
    在微信的官方文档常见错误及解决方法中,只有认证的公众号才具有分享相关接口权限

  • 绑定JS域名
    在 微信公众号 >> 功能设置 >> JS接口安全域名 中配置JS接口安全域名
    MP_verify_1PI6AnuQ7s0acvZv.txt(点击下载)放置在填写的域名目录下

  • 添加IP白名单
    在 微信公众号 >> 基本配置 >> IP白名单 中将访问微信接口的服务器的IP地址添加到白名单中

  • 获取AppID和AppSecret
    将获取的AppID和AppSecret保存
    AppSecret一旦重置,将影响所有使用此AppID的应用,要慎重!

后端工作

参考微信官方文档JS-SDK使用权限签名算法

  • 获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token)
    curl "http://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appId}&secret=${secret}"
    注意:curl测试时,url用“”,否则服务器不通
  • 检查生成的签名
    http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

获取生成签名所需参数

  1. appId + secret -------> ACCESS_TOKEN
  2. ACCESS_TOKEN -------> jsapi_ticket
// 1.获取access_token
app.get('/get_access_token', (req, res) => {
  res.header("Access-Control-Allow-Origin",req.headers.origin); // 处理跨域
  request.get({
    url: `http://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appId}&secret=${secret}`,
    json: true,
  }, (err, response, body) => {
    console.log(body, 'token')
    try {
      if (err) {
        res.json(err);
      } else {
        // 这里获取到ACCESS_TOKEN 传给getticket获取jsapi_ticket
        res.send(body)
      }
    } catch (error) {
      let data = {
        "code": 500,
        "message": "net error"
      };
      res.send(data);
      LOG.error(req.method, req.url, '===========', error);
    }
  });
})
// 2.根据access_token获取jsapi_ticket
app.get('/get_ticket', (req, res) => {
  res.header("Access-Control-Allow-Origin",req.headers.origin);
  request.get({
    url: `http://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${ACCESS_TOKEN}&type=jsapi`,
    json: true,
  }, (err, response, body) => {
    // console.log(body, 'getticket')
    try {
      if (err) {
        res.json(err);
      } else {
        // 这里生成签名 jsapi_ticket
        res.send(body)
      }
    } catch (error) {
      let data = {
        "code": 500,
        "message": "net error"
      };
      res.send(data);
      LOG.error(req.method, req.url, '===========', error);
    }
  });
})

签名过程

  1. 生成随机字符串
  2. 对象进行ASCII码排序
  3. 将排序后的对象用key1=value1&key2=value2形式拼接
  4. 进行sha1加密
  5. 进行签名算法

// 3.1生成随机字符串
let randomString = (length) => {
  let chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
  let result = '';
  for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
  return result;
}

// 3.2对象进行ASCII码排序
let sort_ASCII = (obj) => {
  var arr = new Array();
  var num = 0;
  for (var i in obj) {
    arr[num] = i;
    num++;
  }
  var sortArr = arr.sort();
  var sortObj = {};
  for (var i in sortArr) {
    sortObj[sortArr[i]] = obj[sortArr[i]];
  }
  return sortObj;
}

// 3.3将对象用key1=value1&key2=value2形式拼接
let json_to_string = (jsonObj) => {
  let jStr= ''
  for(var item in jsonObj){
      jStr += item + "=" + jsonObj[item]+ "&";
  }
  jStr = jStr.substring(0, jStr.length - 1);
  return jStr
}

// 3.4进行sha1加密
const encrypt = (algorithm, content) => {
  let hash = createHash(algorithm)
  hash.update(content)
  return hash.digest('hex')
}
const sha1 = (content) => encrypt('sha1', content)

// 3.5进行签名算法
let sign = (jsapi_ticket) => {
  let timestamp = Date.parse( new Date() ).toString().substr(0,10)
  let nonceStr = randomString(16)
  let jsonobj = {
    noncestr: nonceStr,
    jsapi_ticket: jsapi_ticket,
    timestamp: timestamp,
    url: shareUrl
  }
  console.log(jsonobj)

  let str = json_to_string(sort_ASCII(jsonobj))

  console.log(str)

  let signature = sha1(str)

  console.log(signature)

  let data = {
      appId: appId, // 必填,公众号的唯一标识
      timestamp: timestamp, // 必填,生成签名的时间戳
      nonceStr: nonceStr, // 必填,生成签名的随机串
      signature: signature,// 必填,签名
      url: shareUrl
    }
  return data
}

前端工作

  • 安装所需wx依赖
    npm install jweixin-module
  • 引入依赖
    let wx = require('jweixin-module')

通过config接口注入权限验证配置

所有需要使用wx的页面都要先注入配置,否则调用wx方法报错“无权限”
此处所有配置参数由后端传入

wx.config({
        debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
        appId, // 必填,公众号的唯一标识
        timestamp, // 必填,生成签名的时间戳
        nonceStr, // 必填,生成签名的随机串
        signature, // 必填,签名
        jsApiList: ["updateAppMessageShareData", "updateTimelineShareData"] // 必填,需要使用的JS接口列表
      });

通过ready接口处理成功验证

config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。

分享的链接必须是 http or https ,否则不生效

wx.ready(function() {
        // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。

        wx.updateAppMessageShareData({
          title: that.shareTitle, // 分享标题
          desc: that.shareDesc, // 分享描述
          link: that.shareUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
          imgUrl: `https://staticai.xxxx.com/img/share.265ee3fb.jpg`, // 分享图标
          success: function() {
            // 设置成功
            // alert("分享朋友成功");
          },
          fail: function(e) {
            console.log(e, "分享朋友失败");
          }
        });

        wx.updateTimelineShareData({
          title: that.shareTitle, // 分享标题
          link: that.shareUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
          imgUrl: `https://staticai.xxx.com/img/share.265ee3fb.jpg`, // 分享图标
          success: function() {
            // 设置成功
            // alert("分享朋友圈成功");
          },
          fail: function(e) {
            console.log(e, "分享朋友圈失败");
          }
        });

        wx.checkJsApi({
          jsApiList: ["updateAppMessageShareData", "updateTimelineShareData"], // 需要检测的JS接口列表,所有JS接口列表见附录2,
          success: function(res) {
            // 以键值对的形式返回,可用的api值true,不可用为false
            // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
          },
          fail: function(e) {
            console.log(e, "检查jsapi失败");
          }
        });

        wx.error(function(res) {
          // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
          console.log(res, "config失败");
        });
      });

END

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,869评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,716评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,223评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,047评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,089评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,839评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,516评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,410评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,920评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,052评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,179评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,868评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,522评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,070评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,186评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,487评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,162评论 2 356

推荐阅读更多精彩内容