微信内 H5 页面自定义分享

起源:

最近公司在做一个活动的h5页面,在微信内打开时需要进行微信授权,然后后端会重定向到这个页面并且携带了一些参数(openid等)。问题是点击微信的原生分享时,会把携带的这些参数一起分享出去,等于把用户信息泄露了。所以为了解决这个问题,只能实现自定义微信分享的功能,可以自定义分享的地址、标题、图标还有简介。

事先需要做的:

1.微信公众号:必须是经过微信认证的,没有认证的或者认证过期的都不可以;

2.经过备案的域名:必须是备案过的,不然是无法使用的;

3.绑定域名:首先你需要将需要分享的网址的域名绑定到微信公众平台上面,

具体操作:先登录微信公众平台进入“公众号设置”的“功能设置”里填写:JS接口安全域名;还要在"安全中心"中设置:IP白名单


904df06155fe1efcb0dbd63e12c11e99.png

4d7207fc806747794e2033fc35aa5232.png
后台需要做的:

1.后台服务器:前台页面需要后台服务器传过来一些配置参数,比如appId、timestamp、nonceStr、signature这几个参数都是后台从微信公众平台获取到的, 需要后台进行配合;

2.获取access_token:利用公共号APPID、APPSECRET从微信服务器获取对应的access_token,这里是后台开发小伙伴的范围不多做解释;

后台需要传的参数格式:

[图片上传失败...(image-b9822e-1622797016151)]
签名的生成步骤:

生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。

  1. 获取access_token(有效期7200秒,2个小时开发者必须在自己的服务全局缓存access_token):access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。具体请参考以下官方文档:

https://link.zhihu.com/?target=https%3A//developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html

公众号和小程序均可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器IP地址添加到IP白名单中,点击查看设置方法,否则将无法调用成功。小程序无需配置IP白名单。示例代码如下所示:

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

返回的JSON如下:

{"access_token":"ACCESS_TOKEN","expires_in":7200}
  1. 用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,2个小时,开发者必须在自己的服务全局缓存jsapi_ticket)
https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

成功返回JSON如下:

{
  "errcode":0,
  "errmsg":"ok",
  "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
  "expires_in":7200
}
  1. 生成JS-SDK权限验证的签名

参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。

首先:对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:

顺序依次为:jsapi_ticket,noncestr,timestamp,url。

jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW&timestamp=1414587457&url=http://mp.weixin.qq.com?params=value

然后:对string1进行sha1签名,得到signature。

signature=sha1(string1) // 0f9de62fce790f9a083d5c99e95740ceb90c27ed

注意事项

签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
签名用的url必须是调用JS接口页面的完整URL。
出于安全考虑,开发者必须在服务器端实现签名的逻辑。

前端需要做的:

参考官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

1、在项目中引用微信的js-sdk

官方文档上写的是1.6.0

在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.6.0.js

如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.6.0.js (支持https)。

2、配置config

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用。同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用。其中的签名信息signature需要服务器端提供。timestamp和nonceStr是参与签名生成的字段,因此也可以由服务端一并提供,代码如下所示:

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', 
    timestamp: , 
    nonceStr: '', 
    signature: '',
    jsApiList: [] 
});

参数说明:
appId:公众号的唯一标识,在公众号中可以取到;
timestamp:生成签名的时间戳
nonceStr:生成签名的随机串
signature:最后生成的签名
jsApiList:需要使用的JS接口列表,我们这里是用分享接口,将分享几个api接口填进去,例如:['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareQQ']

3、通过ready接口处理成功验证

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

4、通过error接口处理失败验证

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

所有接口通过wx对象(也可使用jWeixin对象)来调用,参数是一个对象,除了每个接口本身需要传的参数之外,还有以下通用参数:

success:接口调用成功时执行的回调函数。
fail:接口调用失败时执行的回调函数。
complete:接口调用完成时执行的回调函数,无论成功或失败都会执行。
cancel:用户点击取消时的回调函数,仅部分有用户取消操作的api才会用到。
trigger:监听Menu中的按钮点击时触发的方法,该方法仅支持Menu中的相关接口。

备注:不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回。

以上几个函数都带有一个参数,类型为对象,其中除了每个接口本身返回的数据之外,还有一个通用属性errMsg,其值格式如下:

调用成功时:"xxx:ok" ,其中xxx为调用的接口名

用户取消时:"xxx:cancel",其中xxx为调用的接口名

调用失败时:其值为具体错误信息

官方示例代码:

自定义“分享给微信朋友”及“分享到QQ好友”按钮的分享内容(JSSDK 1.4.0以上版本支持):

wx.ready(function () {   //需在用户可能点击分享按钮前就先调用
  wx.updateAppMessageShareData({ 
    title: '', // 分享标题
    desc: '', // 分享描述
    link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
    imgUrl: '', // 分享图标
    success: function () {
      // 设置成功
    }
  })
}); 

自定义“分享到朋友圈”及“分享到QQ空间”按钮的分享内容(JSSDK 1.4.0以上版本支持):

wx.ready(function () {      //需在用户可能点击分享按钮前就先调用
  wx.updateTimelineShareData({ 
    title: '', // 分享标题
    link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
    imgUrl: '', // 分享图标
    success: function () {
      // 设置成功
    }
  })
});

获取“分享给朋友”按钮点击状态及自定义分享内容接口(即将废弃):

wx.onMenuShareAppMessage({
  title: '', // 分享标题
  desc: '', // 分享描述
  link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
  imgUrl: '', // 分享图标
  type: '', // 分享类型,music、video或link,不填默认为link
  dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
  success: function () {
    // 用户点击了分享后执行的回调函数
  }
});

获取“分享到朋友圈”按钮点击状态及自定义分享内容接口(即将废弃):

wx.onMenuShareTimeline({
  title: '', // 分享标题
  link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
  imgUrl: '', // 分享图标
  success: function () {
  // 用户点击了分享后执行的回调函数
  }
},

获取“分享到QQ”按钮点击状态及自定义分享内容接口(即将废弃):

wx.onMenuShareQQ({
  title: '', // 分享标题
  desc: '', // 分享描述
  link: '', // 分享链接
  imgUrl: '', // 分享图标
  success: function () {
  // 用户确认分享后执行的回调函数
  },
  cancel: function () {
  // 用户取消分享后执行的回调函数
  }
});

\color{ red}{ 注意: }

如果用旧版的 wx.onMenuShareTimeline、wx.onMenuShareAppMessage、wx.onMenuShareQQ 接口,请用1.4.0或者1.0.0的SDK。

我们用新接口的时候一直提示没有权限,用原接口的时候提示签名错误,后来换了1.0.0的SDK,后台又重新检查了下签名,并把 jsapi_ticket 缓存去掉。主要就是要一步步去测试,然后就神奇的好了。

完整的自定义分享代码:

getWXShare() {
          axios.get('***/***/getShareTicket', MD5({
            url: location.href
          }), function (data) {
            if (data.code === 200) {
              wx.config({
                // debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
                appId: data.data.appId, //后台 必填,公众号的唯一标识
                timestamp: data.data.timestamp, // 必填,后台生成签名的时间戳
                nonceStr: data.data.nonceStr, // 必填,后台生成签名的随机串
                signature: data.data.signature,// 必填,后台签名
                jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareAppMessage','onMenuShareTimeline', 'onMenuShareQQ', 'onMenuShareQZone']
              });

              wx.ready(function () {
                //分享到朋友圈(旧)
                wx.onMenuShareTimeline({
                  title: '要分享的标题', // 分享标题
                  desc: '要分享的简介',
                  link: "要分享的地址", // 分享链接,
                  imgUrl: '要分享图标', // 分享图标
                  success: function () {
                    // 用户点击了分享后执行的回调函数
                    // console.log("分享成功");
                  },
                  cancel: function () {
                    // 用户取消分享后执行的回调函数
                    // console.log("分享取消");
                  }
                });
                // 朋友(旧)
                wx.onMenuShareAppMessage({
                  title: '要分享的标题', // 分享标题
                  desc: '要分享的简介',
                  link: "要分享的地址", // 分享链接,
                  imgUrl: '要分享图标', // 分享图标
                  success: function () {
                    // 用户点击了分享后执行的回调函数
                    // console.log("分享成功2");
                  },
                  cancel: function () {
                    // 用户取消分享后执行的回调函数
                    // console.log("分享取消2");
                  }
                });
              });
              //必须放wx.ready后面 否则无法执行
              wx.error(function(res){
                //config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
              });
            } else {
              alert('请稍后后再试')
            }
          })
},
总结:

到这一步分享的操作基本就完成了,建议在测试时将debug打开,看看分享提示,从而判定是否分享成功。如果不成功,可以参考一下在开发时候遇到的坑。

出现 nvalid url domain 提示
1)检查当前页面所在域名与使用的appid没有绑定,请确认正确填写绑定的域名,仅支持80(http)和443(https)两个端口,因此不需要填写端口号。
出现invalid signature签名错误提示
1)检查生成signature是否正确,可以通过签名校验工具来判定后端传过来的nonceStr、timestamp与请求后端接口传的地址,与最后签名是否一致。

  1. config时,nonceStr 记得驼峰写法。
  2. 签名用的url必须是调用JS接口页面的完整URL,即当前页面的完整URL。
    提示是成功的,但是分享出来图标不见或者desc不显示的情况
    1. 分享的地址不要带端口号。
      2)分享desc 不要带有敏感词汇。
新更新:(2021.12.20)

最近微信新修改了自定义分享规则,通过链接点进来的分享只能分享链接;通过分享和扫码进来的可以分享链接+标题+缩略图。(实测)

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

推荐阅读更多精彩内容