前言
当我们有一个链接想要分享给微信朋友时,有以下几种方法:
-
直接复制粘贴。朋友收到的是一个链接字符串,十分的难看。
-
从其他应用分享到微信:使用手机浏览器或QQ等其他应用打开连接后分享到微信,会发现分享链接会有标题、描述、缩略图。具体展示跟打开的应用有关,如QQ打开的链接标题为网站的title、描述为链接字符串、缩略图为网站的部分截图。
-
微信内分享:使用微信扫一个二维码进入链接,再通过微信分享给朋友,会发现默认情况下分享的标题为网站标题、描述为链接字符串,缩略图为一个svg。
本文主要讨论的是第三种情况,当在微信内进行分享(扫码分享)时,微信提供了 js-sdk
对分享链接进行配置,可以自定义分享链接的标题、描述和缩略图,接下来我们参考 JS-SDK说明文档 一步步的讲解如何配置。
💡 官方文档:JS-SDK说明文档
前期准备
1. 注册公众号
前往 微信公众号平台 注册一个公众号(订阅号或小程序都可以,因为我们要使用的是微信sdk的分享接口,该接口需要进行微信认证,只用企业账号才可以进行微信认证,所以注册的一定要是企业账号!!!)。
2. 登录到微信公众号平台进行一些必要配置
a. 点击左侧菜单栏的”设置与开发“ → ”基本配置“ 可以生成 开发者ID(AppID)
和 开发者密码(AppSecret)
,注意 AppSecret 生成后要自己保存好,之后在微信公众号平台是不会再显示这个密码的,当然如果忘了还是可以重置掉的。(这个 appsecret 主要用于获取Access token,后面会讲到)。
b. 进入到”设置与开发“ → ”公众号配置“ → ”功能设置“ → “JS接口安全域名”的设置页面添加需要调用 js-sdk
的域名,域名要求看下图的注意事项(注意一个月只能修改5次)。
3. 获取AccessToken
使用上面的 appid
和 appsceret
调用以下接口,请求成功会得到access_token和一个过期时间{"access_token":"ACCESS_TOKEN","expires_in":7200}
。
GET <https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET>
建议公众号开发者使用中控服务器统一获取和刷新 access_token,其他业务逻辑服务器所使用的 access_token 均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致 access_token 覆盖而影响业务;过期时间目前是7200秒之内的值,中控服务器需要根据这个有效时间提前去刷新access_token。
4. 添加服务器到白名单
直接调用上面的 获取accessToken接口会发现接口调用失败,这是因为没有配置白名单。
公众号和小程序均可以使用AppID和AppSecret调用获取accessToken接口来获取access_token。调用接口时,请登录“微信公众平台-设置与开发-基本配置”提前将服务器IP地址添加到IP白名单中,点击查看设置方法,否则将无法调用成功。小程序无需配置IP白名单。
如果要使用 Postman来测试接口,如获取 Access Token接口,要将 运行Postman的电脑的 IP 加入到白名单中,否则无法调用成功。
5. 查看自己的公众号是否有接口的使用权限
进入”设置与开发” → ”接口权限“ 页面查看要使用的接口是否有权限。
由于我们要配置微信的分享链接展示,所以我们要使用到“分享接口”。
我们发现“分享接口”需要通过”微信认证“才可以!而且只有企业账号才可以开通微信认证!!!
开发配置
1. 引入js文件
方法一: 直接在html中引入js文件,用 window.wx
获取到 wx 对象
-
在需要调用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)。 -
由于我使用的是 react 框架,直接在 html 文件中引入该 js 文件
// html <script src="<http://res.wx.qq.com/open/js/jweixin-1.6.0.js>" type="text/javascript" ></script> // js const wx = window.wx
方法二: 使用 AMD/CMD 标准模块加载方法加载
-
直接使用
weixin-js-sdk
库import wx from 'weixin-js-sdk'
注意:以上方法二选一,在 html 中引入了 js 使用
weixin-js-sdk
拿到的wx
会是undefined
2. 生成签名(建议后端提供一个接口)
-
获取
jsapi_ticket
- 使用上面获取到的
AccessToken
请求jsapi_ticket
,使用Get请求一下接口即可,返回的ticket
字段即jsapi_ticket
(需要给运行该接口的机器添加白名单,具体可以看上面的“添加服务器到白名单”小节)<https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi>
- 使用上面获取到的
-
生成签名:得到
jsapi_ticket
之后,就可以生成 JS-SDK 权限验证的签名了。-
准备签名需要的参数
noncestr
(随机字符串)- 有效的
jsapi_ticket
timestamp
(时间戳)url
(当前网页的URL,不包含#及其后面部分)
-
将上面的签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1,如下面的例子
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
-
对string1进行sha1签名,得到
signature
:0f9de62fce790f9a083d5c99e95740ceb90c27ed
-
以上就是生成签名的全过程,建议将这段逻辑写在后端,让后端提供一个生成签名的接口供前端调用,接口接受一个url参数(要分享的网页的URL),返回noncestr
、jsapi_ticket
、timestamp
、url
和 signature
。(需要将运行后端接口的机器添加白名单,具体可以看上面的“添加服务器到白名单”小节)
{
nonceStr: string; // 随机字符串
jsapi_ticket: string; // jsapi_ticket
timestamp: string; // 时间戳
url: string; // 要分享的网页URL
signature: string; // 签名
}
获取签名信息参考代码
import crypto from 'crypto-js';
import axios from 'axios'
import random from 'string-random'
const WX_BASE_URL = '<https://api.weixin.qq.com/cgi-bin>'
const APP_ID = 'xxxx'
const APP_SECRET = 'xxxx'
const generatorSha1 = (str) => {
return crypto.SHA1(str).toString(crypto.enc.Hex)
}
/**
* 获取Access token
* 参考:<https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html>
* 注意运行该方法的电脑ip要加到微信公众号后台的IP白名单中
*/
const getAccessToken = async (appId, appSecret) => {
if (!appId || !appSecret) return
const result = await axios.get(`/token?grant_type=client_credential&appid=${appId}&secret=${appSecret}`, { baseURL: WX_BASE_URL });
console.log('getAccessToken: ', result.data, result.data.access_token)
return result.data.access_token
}
/**
* 获签名信息
* @param {*} url - 要分享的网页链接
* @returns
*/
const getSignature = async (url) => {
if (!url) return
const accessToken = await getAccessToken(APP_ID, APP_SECRET)
const getticketResult = await axios.get(`/ticket/getticket?access_token=${accessToken}&type=jsapi`, { baseURL: WX_BASE_URL });
console.log('jsapi_ticket: ', getticketResult.data, getticketResult.data.ticket)
const jsapi_ticket = getticketResult.data.ticket
const nonceStr = random(16) // 'Wm3WZYTPz0wzccnW'
const timestamp = new Date().getTime()
const str = `jsapi_ticket=${jsapi_ticket}&noncestr=${nonceStr}×tamp=${timestamp}&url=${url}`
const signature = generatorSha1(str)
const result = {
nonceStr,
jsapi_ticket,
timestamp,
url,
signature,
appId,
}
console.log('getSignature: ', result, signature)
return result
}
微信 JS 接口签名校验工具:可以在这个链接下验证一下签名是否正确
💡 注意:如果使用的是小程序云开发静态网站托管的域名的网页,可以免鉴权直接跳任意合法合规小程序,调用 wx.config 时 appId 需填入非个人主体的已认证小程序,不需计算签名,timestamp、nonceStr、signature 填入非空任意值即可。
3. 通过config接口注入权限验证配置(前端页面调用)
经过上面的生成签名步骤(实际开发中让后端提供一个生成签名的接口,但这里为了调试方面都使用Postman手动请求得到必要的参数)后,我们有了 noncestr
、jsapi_ticket
、timestamp
,使用这些参数就可以注入配置信息了。
// 参考:<https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html>
import wx from 'weixin-js-sdk'
/**
* 通过config接口注入权限验证配置
* 请在前端页面调用
* @param {Object} params
*/
const wxConfig = async (params) => {
const { appId, timestamp, nonceStr, signature, jsApiList, onReady, onError } = params
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature,// 必填,签名
jsApiList: jsApiList // 必填,需要使用的JS接口列表,具体可以查看JS接口列表:<https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#63>
});
// 通过ready接口处理成功验证
wx.ready(function () {
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
console.log('wx ready')
onReady && onReady()
});
// 通过error接口处理失败验证
wx.error(function (res) {
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
console.error('wx error', res)
throw Error(res)
});
}
将debug 设置为 true
时,每个 wx api
被调用都会弹出一个弹框(如下图),errMsg 为 config:ok 表示调用成功。上线时记得把 debug 设置为 false
4. 调用分享朋友和分享朋友圈配置api
确保传给 api 的 link 跟 获取签名时使用的 url 完全一致,并且该 url 所在的域名已添加到”公众号后台”的“JS接口安全域名”中,否则调用 api 会失败(报错:”fail link must be in js secure domain list” 或“invalid signature”)
export const shareApp = (params) =>
{
const { title, desc, link, imgUrl } = params
// 自定义“分享给朋友”及“分享到QQ”按钮的分享内容
wx.updateAppMessageShareData({
title, // 分享标题
desc, // 分享描述
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success: function ()
{
// 设置成功
console.log('分享给朋友配置成功')
}
})
// 自定义“分享给朋友”及“分享到QQ”按钮的分享内容
wx.updateTimelineShareData({
title, // 分享标题
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success: function ()
{
// 设置成功
console.log('分享朋友圈配置成功')
}
})
// 获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口
wx.onMenuShareWeibo({
title, // 分享标题
desc, // 分享描述
link, // 分享链接
imgUrl, // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
console.log('分享到腾讯微博成功')
},
cancel: function () {
// 用户取消分享后执行的回调函数
console.log('取消分享到腾讯微博')
}
});
}
最终代码
调用 wxConfig
时注意要把使用到的接口赋值给 jsApiList
,否则会调用失败。
// 参考:<https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html>
import wx from 'weixin-js-sdk'
/**
* 通过config接口注入权限验证配置
* 请在前端页面调用
* @param {Object} params
*/
const wxConfig = async (params) => {
const { appId, timestamp, nonceStr, signature, jsApiList, onReady, onError } = params
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature,// 必填,签名
jsApiList: jsApiList // 必填,需要使用的JS接口列表,具体可以查看JS接口列表:<https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#63>
});
// 通过ready接口处理成功验证
wx.ready(function () {
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
console.log('wx ready')
onReady && onReady()
});
// 通过error接口处理失败验证
wx.error(function (error) {
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
console.error('wx error', error)
onError && onError(error)
});
}
/**
* 微信Api初始化
* 请在需要分享的前端页面调用
* @param {Object} url -需要分享的前端页面
*/
export const wxShareInit = async (url) => {
const data = await getSignature(url) // 后端提供的获取签名api,具体实现可以看上面的”获取签名信息参考代码”小节
const { appId, timestamp, nonceStr, signature } = data
wxConfig({
appId,
timestamp,
nonceStr,
signature,
jsApiList: [
// 分享需要用到以下几个接口
'updateAppMessageShareData', // 自定义“分享给朋友”及“分享到QQ”按钮的分享内容
'updateTimelineShareData', // 自定义“分享给朋友”及“分享到QQ”按钮的分享内容
'updateTimelineShareData', // 获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口
],
onReady: () => {
console.log('初始化成功')
shareApp({
title: '我的自定义标题',
desc: '我的自定义描述',
link: url,
imgUrl: '缩略图url',
}) // 分享配置
},
onError: (error) => {
console.log('初始化失败', error)
}
})
}
在需要分享的页面调用 wxShareInit
方法。
try {
const url = window.location.href.split('#')[0]
wxShareInit(url)
} catch (error) {
console.error(error)
}
验证效果
将要分享的页面链接生成一个二维码,然后微信扫码打开链接,然后点击微信右上角图标进行分享(注意:要确保点击该分享按钮前wxShareInit
已经执行过了,代码中建议一进入页面就调用wxShareInit
),可以发现 标题、描述和缩略图都配置成我们想要的效果啦!
遇到问题
遇到问题可以先去 JS_SDK说明文档-常见错误及解决方法 看看有没有相同的问题。开发过程中的大部分报错都可以在这里面找到。
以上就是自定义微信分享链接展示的所有内容啦。