在特殊地区科学使用 Disqus 评论系统

2020-05-05 笔记本
Cover Image

前一阵子将博客评论系统切换到 Disqus。但在某些特殊地区,由于不可抗拒的缘故,Disqus 不能很好地加载。当然我们不去讨论关于此类「Tom and Jerry」游戏双方合理性,而是看看能否补救。好在 Disqus 无法访问也不是一两天,网络上也已经涌现一批解决方案。

订正:Sukka 提供的 API 并非受到干扰,而是由于使用者过多不得不开启严格的 WAF 限制。但即便如此还是建议自己搭建反代,DisqusJS 的 README 中介绍了 4 中免费无后端反代样例。

DisqusJS#

Disqus 作为目前市场最庞大的第三方评论系统,惨遭干扰有点在所难免,但是还是有许多人执着于此评论系统。为了改善 Disqus 在特殊地区的体验,Sukka 制作了一款 纯前端 的「评论基础模式」实现工具:DisqusJS。它会自动判断用户 Disqus 可访问性,若可以访问则直接连接,对于无法正常访问的用户通过 Disqus API 渲染评论数据

Cloudflare Workers 反代#

当初刚换上 Disqus 时也想过利用 Cloudflare Workers 直接反代 Disqus 域名,但是初次尝试立马遇到问题。且先不提 Disqus 的众多 CDN 域名,单是代理 disqus.com 就会导致页面内登陆的 reCapture 无法加载,自然也就无法成功登陆。

DisqusJS 就不一样,它利用 Disqus API 渲染评论。虽然 Disqus API 也惨遭毒手,但是只需反代一个 API 便可完整渲染评论。相比之下这种方法显然更可行。

在 Cloudflare 中新建一个 Worker,将下述代码替换原有代码。

addEventListener('fetch', event => {
event.respondWith(proxy(event));
});

async function proxy(event) {
const getReqHeader = (key) => event.request.headers.get(key);

let url = new URL(event.request.url);
url.hostname = "disqus.com";

let parameter = {
headers: {
'Host': 'disqus.com',
'User-Agent': getReqHeader("User-Agent"),
'Accept': getReqHeader("Accept"),
'Accept-Language': getReqHeader("Accept-Language"),
'Accept-Encoding': getReqHeader("Accept-Encoding"),
'Connection': 'keep-alive',
'Cache-Control': 'max-age=0'
}
};

if (event.request.headers.has("Referer")) {
parameter.headers.Referer = getReqHeader("Referer");
}

if (event.request.headers.has("Origin")) {
parameter.headers.Origin = getReqHeader("Origin");
}

return fetch(new Request(url, event.request), parameter);
}

之后便可使用 https://[ domain ]/api/ 无痛访问 Disqus API 了。即便不绑定自定义域名,也可以直接通过 https://[ Worker Name ].xxx.workers.dev/api/ 访问。

Disqus API 申请#

Disqus API Resources 新建一个 Application。

将基础信息完善后,点击「Redister my application」确认新建,然后点击新创建的 Application,在「Details」中获取你的 API Keys 与 API Secrets。

接着切换到「Settings」中,设置域名白名单防止其他用户滥用你的 API,还能防止某些安全隐患。

DisqusJS 配置#

如果你在使用 Hexo 主题「Cards」 或者其他内置 DisqusJS 的博客程序,你可以直接根据 DisqusJS 配置项 填写相关信息。

如果你使用的博客程序没有内置该功能,则需要手动配置初始化脚本。

首先你需要准备一个 #disqus_thread 容器,Disqus/DisqusJS 会在该容器内加载。

<div id="disqus_thread"></div>

紧接着你需要在需要加载评论系统的页面引入 DisqusJS 的 JS 和 CSS 资源,推荐使用 CDN 加载。我们这里使用了 jsDelivr 公共 CDN。

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/disqusjs@1.3/dist/disqusjs.css">
<script src="https://cdn.jsdelivr.net/npm/disqusjs@1.3/dist/disqus.js"></script>

在加载完上述 DisqusJS 资源后,使用脚本初始化 DisqusJS 实例。也还请参考 DisqusJS 配置项 填写相关信息。

<script>
var dsqjs = new DisqusJS({
shortname: '',
siteName: '',
identifier: '',
url: '',
title: '',
api: '',
apikey: '',
admin: '',
adminLabel: ''
nesting:
});
</script>

至此,只要用户所在地区没有封锁 Cloudflare,都可以以较好体验阅读评论,但倘若希望参加评论互动可能还是需要代理。

Lazyload#

虽然 DisqusJS 能极大改善特殊地区用户体验,但是「能做到」仍与「能做好」有不小差距。从 Chrome 控制台可以发现,整个网页除了 Disqus 就只有 50KB 左右,但是加载 Disqus 瞬间去到 1.6MB,网站性能方面确实还有很大提升空间。

既然要用 Disqus,总不能不加载了。可是评论区通常都在正文底部,倒也不是一上来就需要加载,往往还会堵塞后续资源加载。所以我们可以使用 Lazyload 按需加载 Disqus,仅当元素可见时才开始加载。

这种做法很自然,当然已经有前辈想到。我再在其基础上稍加修改,就连 DisqusJS 的 JS 和 CSS 资源也放入 Lazyload 加载。只要注意初始化脚本必须在加载 DisqusJS 的 JS 和 CSS 资源之后执行就可以很快实现。

DisqusJS 初始化中的 disqus_page_urldisqus_page_identifier 是页面判断依据,通常使用 URL 来判定页面)。

Lazyload 脚本(自行修改 disqusJS.js 路径)

// lazyDisqus.js

function callback() {
window.disqus_config = function () {
this.page.url = disqus_page_url;
this.page.identifier = disqus_page_identifier;
}
new DisqusJS({
shortname: '',
siteName: '',
identifier: disqus_page_identifier,
url: disqus_page_url,
title: '',
api: '',
apikey: '',
admin: '',
adminLabel: ''
nesting:
});
}

function addStyle(url) {
var d = document.createElement('link');
d.rel = 'stylesheet';
d.href = url;
document.head.appendChild(d);
}

function addScript(url) {
var d = document.createElement('script');
d.src = url;
d.async = false;
document.body.appendChild(d);
d.onload = () => {
callback();
}
}

function loadDisqus() {
addScript('https://cdn.jsdelivr.net/npm/disqusjs@1.3/dist/disqus.js');
addStyle('https://cdn.jsdelivr.net/npm/disqusjs@1.3/dist/disqusjs.css');
}

var runningOnBrowser = typeof window !== "undefined";
var isBot = runningOnBrowser && !("onscroll" in window) || typeof navigator !== "undefined" && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent);
var supportsIntersectionObserver = runningOnBrowser && "IntersectionObserver" in window;

setTimeout(function () {
if (!isBot && supportsIntersectionObserver) {
var disqus_observer = new IntersectionObserver(function(entries) {
if (entries[0].isIntersecting) {
loadDisqus();
disqus_observer.disconnect();
}
});
disqus_observer.observe(document.getElementById('disqus_thread'));
} else {
loadDisqus();
}
}, 0);

然后在需要加载 Disqus 评论页面的 </body> 前加上加载代码(自行修改 lazyDisqus.js 路径)

<script defer src="lazyDisqus.js"></script>

#

据说 Disqus 是第三方评论系统鼻祖,平台强大,同时与 Akismet 合作让你的站点不太容易出现垃圾评论。

这里 Lazyload 脚本调用 IntersectionObserver 实现,主流现代浏览器都有支持。除非你真的很在意旧版 IE 用户,否则不建议还通过绑定 sroll 事件实现 Lazyload。

将 Disqus Lazyload 带来的性能跃迁肯定能为你网站权重砍下许多性能分数。而 Google 等搜索引擎的爬虫也有针对 IntersectionObserver 优化,这样搜索引擎的能抓取被 Lazyload 的内容,说不定对 SEO 还有帮助。

于是乎,在「特殊地区」的 Disqus 使用也算被调教成一个舒服的样子了。


关联阅读/参考连接:

https://github.com/SukkaW/DisqusJS

https://blog.skk.moe/post/prevent-disqus-from-slowing-your-site/

本文作者:ChrAlpha

本文链接: https://blog.ichr.me/post/use-disqus-conveniently/

文章默认采用 CC BY-NC-SA 4.0 协议进行许可,使用时请注意遵守协议。

笔记本

评论

您所在的地区可能无法访问 Disqus 评论系统,请切换网络环境再尝试。