缘由
有一天,我看到这篇文案:实践:使个人网站在微X/QQ中被优雅地拜访 - 小站背面。我才发掘,个人网站倘若无尤其在微X那边设置的话,在微X里面分享出来的效果很差,仅有一个链接符号,以及网站的标题。
倘若是在浏览器端分享,或许还好一点。例如我用 iPhone 的 Safari 浏览器,分享到微X就可以展示标题、头图和简介。这些应该是网页的有些<meta> 标签在起功效,详细那些就不晓得了,由于我的网站中一堆这种功能的标签。
网页分享给联系人的效果,上面是 Safari 分享到微X,下面是微X内分享
网页分享到伴侣圈的效果,上面是 Safari 分享到微X,下面是微X内分享
前面说到的文案中,针对微X的这种限制这么描述:
微X的链接描述和缩略图并不是自动获取,而是手动定义的。而为何咱们普通人分享时无看到关联选项呢?由于这是一个白名单功能,是附庸于微X公众号的一项功能。简言之,你想要自定义卡片样式,你就必须申请一个公众号,并将自己的域名接入该公众号后台。
雪上加霜的是,这一步需求域名已备案。
我的域名是备案过的,况且我亦有公众号,我倒是想晓得怎么搞。
然则,我找了一下微X公众号的后台,无关联的设置。
我搜了一下,发掘,原来这个功能用的是微X公众平台的 JS-SDK。文档 里面写的比较仔细,能够瞧瞧。
我日前的博客是基于 Hexo 的静态博客,运用 安知鱼主题的魔改版本。
基本过程
微X公众平台的 JS-SDK 中,调用之前必须生成签名。研发者必要在服务器端实现签名的规律。
总的来讲,想要为在微X内分享的外链添加照片和简介,分为以下几个过程:
1、绑定域名:公众号设置 → 功能设置 → JS 接口安全域名
绑定域名
2、设置 IP 白名单:仅支持 IPv4 格式的位置;这儿亦能看到 AppID 和 AppSecret(倘若没设置的话生成一下,记下来)
3、在页面引入 JS 文件:http://res.wx.qq.com/open/js/jweixin-1.6.0.js
4、在白名单所在网络获取 access_token: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET// 正常状况下
{"access_token":"ACCESS_TOKEN","expires_in":7200}5、在白名单所在网络获取 jsapi_ticket: GEThttps://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi// 正常状况下
{
"errcode":0,
"errmsg":"ok",
"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in":7200
}6、经过特定的签名算法生成签名 signature,详见文档。除了前面得到的 jsapi_ticket,还要传入秒为单位的时间戳 timestamp、随机字符串 noncestr 和调用 JS 接口页面的完整 URL url(路径要在绑定域名下)。
7、注入权限验证配置: wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,能够在pc端打开,参数信息会经过log打出,仅在pc端时才会打印。
appId: APPID, // 必填,公众号的独一标识
timestamp: TIMESTAMP, // 必填,生成签名的时间戳
nonceStr: NONCESTR, // 必填,生成签名的随机串
signature: SIGNATURE,// 必填,签名
jsApiList: [
updateAppMessageShareData,
updateTimelineShareData
] // 必填,必须运用的JS接口列表。上面写了本例中必须的接口
});8、自定义“分享给伴侣”及“分享到 QQ”按钮的分享内容,以及“分享到伴侣圈”及“分享到 QQ 空间”按钮的分享内容: wx.ready(function () {//需在用户可能点击分享按钮前就先调用
wx.updateAppMessageShareData({ ... })
wx.updateTimelineShareData({ ... })
});处理签名的问题
研发者必要在服务器端实现签名的规律,况且 access_token 和 jsapi_ticket 的获取都要在 IP 白名单内进行,并存储,有效期内不该重新请求。因此呢,咱们一样必须在服务器端获取 access_token 和 jsapi_ticket。
因为 Hexo 生成的文件是一堆静态文件,倘若想这么搞就要另起炉灶,专门写一套服务用来生成它们、处理签名。
我不太想写,就找有无现成可用的,最后找到了一个运用 Express 框架的 JS 项目:「链接」。能够调用它供给的 API,直接得到签名: GET /api/getWechatJsapiSign/?noncestr=NONCESTR×tamp=TIMESTAMP&url=URL{"signature": "aaaabbbbbbbbbbbbbb"}后端 Docker 化
因为我几乎所有服务器上的服务都用 Docker 镜像托管,因此我自然就想将它打包为 Docker 镜像,这般安排的时候方便有些。
因为它必须运用 Redis 存储 access_token 和 jsapi_ticket的信息,因此呢我运用 Redis 镜像为基本,安装 Node.js,起步。
原来的项目由 config.js 写入配置项: exports.weixin = {
AppId: wx9999999999,
AppSecret: ad73709c6e0815c999999999999
};
我为了安排安全方便,所有改为读取环境变量: exports.weixin = {
AppId: process.env.APP_ID,
AppSecret: process.env.APP_SECRET
};ENV APP_ID=wx9999999999
ENV APP_SECRET=ad73709c6e0815c999999999999
这般一来,安排时只必须传入环境变量就可: docker run \
... \
-e APP_ID=wx9999999999 \
-e APP_SECRET=ad73709c6e0815c999999999999 \
dingjunyao/wx_jsapi_sign:latest
在 Docker 里面起步一个服务容易,然则同期起步两个服务,并且还要输出日志,就麻烦了。运用 dumb-init,便能够经过简单的 Shell 脚本,容易实现同期开启多个服务: #!/bin/bash
redis-server &
node app.jsCMD ["/usr/bin/dumb-init", "--", "bash", "start.sh"] # start.sh 即上面的 Shell 脚本倘若镜像在 Debian 的基本上构建,用 APT 就可安装,不必须另一添加软件源: RUN apt-get update -y && \
apt-get install -y dumb-init
仔细的更改见我 fork 的项目:GitHub - DingJunyao/wx_jsapi_sign: The Nodejs server for manage Wechat (Wexin) access_token, jsapi ticket and signature generation. 用于管理微XJS API的access_token、ticket和按照参数生成签名
。我同期把镜像发布到了 Docker Hub (dingjunyao/wx_jsapi_sign) 和 GitHub Packages( ghcr.io/dingjunyao/wx_jsapi_sign)。
前端的操作
实质上,上面的操作是我后来发掘的。我在 Hexo 主题上折腾了半天,才发掘还要搞后端。
我上次大段写前端代码,还是在 2018 年做课设的时候。五年过去了,此刻的前端早已变得亲妈都不认识了。例如我日前的博客项目,除了 Hexo 及附带的各样插件负责管理、渲染、安排等操作外,运用的主题亦采用 pug 模板引擎,以及 stylus 样式引擎。这带来的后果便是,我这种习惯于 HTML + CSS + JS(还是那种最基本的 JS,此刻发展的各项技术我早已跟不上了,哪怕是号叫作入门 ES6 的文档都看不懂) 的外行人,面对此刻的代码,只能摸着石头过河,照着已有的代码,猜测其含义,小修小改。调试则变得反常困难:在浏览器上看到的是渲染后的版本,内容、样式有什么不对的,很大程度上只能靠猜。我通常的做法,便是找到可能是标志性的属性和值,在项目里查询这段文本显现的位置,而后据此修改。
我大致的操作如下: 照着主题里面引入配置的方式,照着写微X的配置项和引入它的脚本照着主题里面引用 JS 的办法,引入微X的 JS API复制主题中的一个 JS 文件,找到可能用得上的片段,魔改。简单来讲,便是经过 fetch 拜访签名 API,而后按照得到的签名进行微X JS-SDK 的各项操作,包含注入配置、应用 API。我不想大段放代码,有兴趣的能够看 GitHub 上 DingJunyao/hexo-theme-anzhiyu-ding-mod 在 2023-10-17 的提交记录。
这种方式极易漏写变量等字符,因此呢我花了两天的时间才改好。
处理跨域问题
本地安排好后,我初次测试,发掘报跨域关联的错误。简单搜索后,我在后端添加了 cors 包,并运用它。
实质上,只要在添加路由前执行以下语句就能够处理问题了: const cors = require(cors);
app.use(cors());然则我期盼能够指定准许的域,于是这么写: const cors = require(cors)
if (config.whitelist.join(,) === ) {
app.use(cors());
} else {
varcorsOptions = {
origin:function (origin, callback) {
console.log(config.whitelist);
if (config.whitelist.indexOf(origin) !== -1) {
callback(null, true)
}else {
callback(new Error(Not allowed by CORS: + origin + not in + config.whitelist))
}
}
};
app.use(cors(corsOptions));
}而 config.whitelist 一样是从环境变量那里读取: exports.whitelist = (process.env.WHITELIST || ).split(,)然则它的值,我琢磨了半天,才发掘,倘若不处理的话,除了端口号之外,协议亦要写上: https://4ading.com
https://4ading.com,http://localhost:4000
折腾了两天才发掘无权限
在浏览器上很难看出来微X关联的代码是不是正确运行,必须在微X研发者工具里面才可看到。
微X研发者工具
注入权限验证配置的时候,我调试了大半天,总算看到 config ok 的提示了。然则,后续的操作仍然失败。而后我发掘,config ok 的时候,返回的 jsApiList 列表为空。
配置成功但无 API 被调用
我还挺纳闷,把 config 里面的文本改为办法: jsApiList:[
wx.updateAppMessageShareData,
wx.updateTimelineShareData
]
还是不行。
后来我不知为何,到自己的接口权限里面一看:
接口权限
这下最终明白了。经过微X认证的公众号才可调用这些功能,而注册主体为个人是搞不了认证的。
搞了两天,才发掘自己一起始就无权限。
败中有成
本来到了这儿,我想把代码弃之不消了,不外还是觉得可惜,可是我无能用的号拿来测试效果。
所幸,微信的研发者工具中还供给了公众平台测试账号,能够测试必须权限的接口。你必须用自己的微X账号登录、关注测试号,而后用它的 appID 和动态变化的 appSecret 来测试。
测试号管理界面
我用它测试了一下,可行。
测试号下的执行结果
趁着还有效,我测试了添加代码后,在微X里面分享出来的效果,结果如下:
添加代码后,网页分享给联系人的效果
添加代码后,网页分享到伴侣圈的效果
因此,虽然自己用不了,然则还是写出了可用的代码。
|