自定义第三方网站微信分享封面图、标题和摘要

如果你尝试过把第三方网站分享微信,可能会发现,很多网站分享到微信之后显示的标题、缩略图和摘要都是默认值。

自定义第三方网站微信分享封面图、标题和摘要插图

在默认情况下,微信会抓取网页的 title,摘要会显示 URL,缩略图则是默认图片,看起来很不美观,信息也不丰富。

作为网站开发者,我当然是希望能自定义微信分享卡片的。研究了下文档,发现这个过程还是有些麻烦的,并且需要后端参与。于是鼓捣了一下,现在已经可以分享出好看的卡片了。

自定义第三方网站微信分享封面图、标题和摘要插图1

整体思路

微信提供了 JSSDK 用于自定义,前端网页需要引入这个 SDK。SDK 需要在初始化和鉴权之后才能使用,所以这里有一个生成签名和鉴权的流程,而生成签名需要在后端进行。后端鉴权是使用的 JS API ticket,这个 ticket 要用 access token 换取。因此,我们实现这个 feature 的整体思路是:

  1. 后端获取 access token,并使用 access token 换取 JS API ticket。
  2. 使用 ticket 生成签名,将签名返回前端。
  3. 前端 SDK 使用签名进行鉴权和初始化。
  4. 设置文章分享的标题、封面图和摘要。

获取 JS API ticket

在获取 JS API ticket 之前,我们需要先获取 access token,这里的步骤可以参考这一篇文章

这个 ticket 和 access token 很相似,都有一定长度的有效期,也都有获取频率的限制,所以当然也需要使用 Redis 进行缓存。需要取 ticket 时,优先从 Redis 获取,取到了就直接返回;如果没取到,再用 access token 向微信接口请求。

module.exports = async (ctx) => {
try {
let jsApiTicket = await ctx.redis.get('wechatJsApiTicket');
if (!jsApiTicket) {
const accessToken = await getAccessToken(ctx);
if (!accessToken) {
throw new Error('get access token error');
      }
const res = await axios.get(`${api.wechat.getJsApiTicket}?access_token=${accessToken}&type=jsapi`);
if (res?.status !== 200) {
throw new Error('get js api ticket error');
      }
      jsApiTicket = res?.data?.ticket;
const expiresIn = res?.data?.expires_in;
if (!jsApiTicket) {
throw new Error('get js api ticket error');
      } else {
await ctx.redis.set('wechatJsApiTicket', jsApiTicket);
await ctx.redis.expire('wechatJsApiTicket', expiresIn);
      }
    }
return Promise.resolve(jsApiTicket);
  } catch (err) {
return Promise.reject(err);
  }
};

生成签名

微信 JS SDK 每个不同 URL 的页面都需要进行初始化和鉴权,需要把 URL 作为参数参与签名的生成。所以,前端向后端发请求时需要把当前页面的 URL 带上。

request.get(api.service.wechat.getJsSdkSignature, {
params: {
url: window.location.href,
  },
})

后端接到前端请求后,取出 URL 参数,按照微信提供的算法生成签名。

module.exports = async (ctx, url) => {
try {
// 刚才封装的获取 JS API ticket 的方法
const jsApiTicket = await getJsApiTicket(ctx);
if (!jsApiTicket) {
throw new Error('get js api ticket error');
    }
// 生成随机字符串
const randomString = RandomString.generate(16);
// 生成时间戳
const timestamp = (Number(new Date()) / 1000).toFixed(0);
// 按照微信给定的格式拼接几个生成签名的参数
const rawString = `jsapi_ticket=${jsApiTicket}&noncestr=${randomString}&timestamp=${timestamp}&url=${url}`;
// 使用 sha1 算法生成签名
const signature = sha1(rawString);
// 把签名及生成签名的随机字符串和时间戳返回
return Promise.resolve({
      randomString,
      timestamp,
      signature,
    });
  } catch (err) {
return Promise.reject(err);
  }
};

这里生成签名除了要用到前端页面 URL 和 JS API ticket 之外,还需要使用一个随机字符串和一个时间戳。需要注意的是,时间戳需要换成以秒为单位的。另外,生成的随机字符串和和时间戳也需要返回给前端。

前端 SDK 鉴权和初始化

第一步,前端首先需要引入这个 SDK。从微信官方地址引入 JS 文件即可。

script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js">script>

引入 JS 文件之后,wx 这个对象就会被挂载在 window 上。如果你使用的是 TS,那么你需要为 window 添加类型定义。

interface WechatConfigProps {
  debug?: boolean;
  appId: string;
  timestamp: number;
  nonceStr: string;
  signature: string;
  jsApiList: string[];
}

interface UpdateAppMessageShareDataProps {
title: string;
  desc: string;
  link: string;
  imgUrl: string;
}

interface UpdateTimelineShareDataProps {
title: string;
  link: string;
  imgUrl: string;
}

interface WechatObject {
config: (props: WechatConfigProps) => void;
  ready: (callback: () => void) => void;
  updateAppMessageShareData: (props: UpdateAppMessageShareDataProps) => void;
  updateTimelineShareData: (props: UpdateTimelineShareDataProps) => void;
}

interface Window {
wx: WechatObject;
}

在向后端请求签名后,就可以在前端初始化微信 JS SDK 了。

request.get(api.service.wechat.getJsSdkSignature, {
params: {
url: window.location.href,
  },
}).then((res) => {
if (res.status === 200) {
window.wx.config({
appId: '微信公众号的 appid',
timestamp: Number(res.data.timestamp),
nonceStr: res.data.randomString,
signature: res.data.signature,
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'],
    });
  }
});

设置分享到微信的标题、封面图和摘要

微信 JS SDK 初始化完成之后,就可以设置分享的样式和信息了。这里需要注意,window.wx.config 是一个异步函数,并且没有提供回调或者 Promise 形式的返回。如果我们调用完 config 之后立即设置分享信息,并不会起作用。不过这个 SDK 提供了 ready 函数,它的参数是一个函数,放在这个函数里面的内容会保证在 config 函数执行成功之后再执行。

window.wx.ready(() => {
window.wx.updateAppMessageShareData({
title: '文章标题',
desc: '摘要',
link: '网页 URL',
imgUrl: '分享封面图',
  });
window.wx.updateTimelineShareData({
title: '文章标题',
link: '网页 URL',
imgUrl: '分享封面图',
  });
});

在 wx.ready 的回调中分别为消息分享卡片和朋友圈分享设置好标题、摘要、URL 和缩略图之后,就大功告成了。

 

发表评论

后才能评论