让多说评论框完美支持 HTTPS

我的博客之前一直部署在 Linode,使用 Disqus 提供的评论服务。Disqus 作为第三方社会化评论的鼻祖,无论功能还是体验,都堪称完美。虽然之前 Disqus 经常加载失败,我也一直在坚守。最近我的 Linode 持续无法访问,几番折腾之后还是换到国内云主机并备案了。借着这次机会,我也把评论从 Disqus 迁移到了国内的多说。多说官方对 HTTPS 的支持并不完美,本文记录我对它的几处改造。

Disqus 和多说都是根据指定 ID 进行评论聚合的第三方系统,将页面上 Disqus 的引用代码换成多说的代码,再按照文档改改参数,评论功能就迁移完成了。数据迁移可以使用前人造好的轮子,例如 Github 上的 GavinFoo/DISQUS2DUOSHUO。功能和数据迁移都很简单,这里略过不写。

我的网站配置了 CSP 策略,需要把多说用到的域名配置到白名单之中。以下是本站 CSP 全部规则:

content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: https://*.duoshuo.com; img-src 'self' data: https://*.duoshuo.com; style-src 'self' 'unsafe-inline' https://*.duoshuo.com; connect-src wss://*.duoshuo.com:* https://*.duoshuo.com

多说的种子文件支持 HTTPS,直接把官方地址替换为 HTTPS 即可。但多说有几个地方没考虑周到,需要额外处理:1)用户头像,多说支持多种第三方登录方式,用户头像也支持使用了第三方地址,而这些地址基本都是 HTTP;2)表情,在多说选择表情的浮层中,只有 wordpress 分组中的表情放在多说服务器上并支持 HTTPS,其余分组全部直接使用了 Sina 微博的 HTTP 地址。另外多说评论正文中的表情,也需要替换为 HTTPS 地址。

要解决用户头像问题,可以借用本站 HTTPS 做一个反向代理。我在 Nginx 配置增加了以下内容:

proxy_cache_path    /home/xxx/proxy_cache_path levels=1:2 keys_zone=pnc:300m inactive=30d max_size=10g;
proxy_temp_path     /home/xxx/proxy_temp_path;
proxy_cache_key     $host$uri$is_args$args;

server {
    ... ...

    location ~ ^/proxy/(\w+\.)(bdimg\.com|cdncache\.org|douban\.com|gravatar\.com|qlogo\.cn|sinaimg\.cn|xnimg\.cn)(\/.*)$ {
        valid_referers blocked server_names;
        if ($invalid_referer) {
            return 403;
        }

        proxy_connect_timeout    10s;
        proxy_read_timeout       10s;

        proxy_pass               http://$1$2$3;

        proxy_cache              pnc;
        proxy_cache_valid        200 30d;
        proxy_cache_lock         on;
        proxy_cache_lock_timeout 5s;
        proxy_cache_use_stale    updating error timeout invalid_header http_500 http_502;

        add_header               X-Cache "$upstream_cache_status from cache.ququ";

        expires                  max;
    }

    location ~ ^/proxy/(.*)$ {
        valid_referers blocked server_names;
        if ($invalid_referer) {
            return 403;
        }

        rewrite       ^.*$ /static/img/blog/default_avatar.png last;
    }

    ... ...
}

以上配置做了几件事情:1)针对白名单中的 URL 做了反向代理,针对白名单之外的 URL 输出默认头像;2)通过 Nginx 的 proxy_cache 以及 HTTP 的缓存机制,增加访问速度;3)针对这个 proxy 服务启用了严格的 referer 限制(空 referer 都不允许)。

有了反向代理之后,可以对多说的 embed.js 动手术了。我没有找到无侵入的补丁方式,只能粗暴地将官方 embed.js 托管在本站进行修改。一共修改了以下几处(为了看得更清楚,我加入的代码放在注释里):

avatarUrl: function(e) {
    /*
    if (e.avatar_url) {
        e.avatar_url = e.avatar_url.replace(/^http\:\/\//, "https://imququ.com/proxy/");
    } else {
        nt.data.default_avatar_url = '/static/img/blog/default_avatar.png';
    }
    */

    return e.avatar_url || nt.data.default_avatar_url
}

这处修改,是让多说用户头像走前面配置的 proxy 服务。对于无头像用户,我直接返回了默认头像地址,减少一次 proxy。

addSmilies = function(e, t) {
    /*
    if(e !== 'WordPress') return;
    */

    var s = j.smiliesTooltip;
    s && s.el.find("ul.ds-smilies-tabs").append("<li><a>" + e + "</a></li>"), j.smilies[e] = t
}

这处修改,是让多说不加载 Wordpress 之外的分组表情。由于只剩下一个分组,所以表情浮层样式我也微调了一下,具体效果请看本文评论(实际上,多说评论的样式我改了好多处)。将 Sina 微博表情替换为 proxy 地址,或者是传到支持 HTTPS 的 CDN 也可以,但我觉得没有必要。如果图省事,也可以直接在多说后台关闭评论表情功能。

var t = "",
    s = e.post,
    i = e.options,
    r = s.author;

/*
s.message = s.message.replace(/http:\/\/static\.duoshuo\.com\//g, 'https://static.duoshuo.com/');
*/

if (t += '<li class="ds-post" data-post-id="' + s.post_id + '">...'){
    ...
}

这处修改,是将评论内容中的表情地址由 HTTP 替换为 HTTPS。

经过以上处理,多说评论所需资源全部会走 HTTPS 了。由于多说代码会更新,本文具有一定的时效性,大家可以参考我的做法自行修改,不要照搬代码。

另外,多说没有 Disqus 那样的新评论通知邮件,我是通过 Github 上的 zhengxiaopeng/duoshuo-comment-notification 项目实现即时提醒的。

最后,我在迁移 Disqus 到多说的过程中,参考了以下两篇文章,在此表示感谢:

注:一番折腾之后,我还是回归了 Disqus,详情请见 »

本文链接:参与评论 »

--EOF--

提醒:本文最后更新于 421 天前,文中所描述的信息可能已发生改变,请谨慎使用。

Comments