ChrAlpha's Blog

Thumbnail-%E5%9C%A8%E7%89%B9%E6%AE%8A%E5%9C%B0%E5%8C%BA%E7%A7%91%E5%AD%A6%E4%BD%BF%E7%94%A8%20Disqus%20%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F

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

2020-05-05·笔记本

前一阵子将博客评论系统切换到 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。

unalted image

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

unalted image

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

unalted image

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,网站性能方面确实还有很大提升空间。

unalted image

既然要用 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 使用也算被调教成一个舒服的样子了。


参考链接

在特殊地区科学使用 Disqus 评论系统
本文作者
ChrAlpha
发布日期
2020-05-05
更新日期
2020-05-05
转载或引用本文时请遵守 CC BY-NC-SA 4.0 许可协议,注明出处、不得用于商业用途!
CC BY-NC-SA 4.0