一开始博客本来想用disqus的,但是它被墙了,所以退而求其次选择gitment,但是它每次写完文章都需要初始化评论,而且它需要的权限比较高,而且需要评论在issue中,在github首页默认展示评论的issue,看起来好不爽- -所以我想着做一个小轮子,把闲置的云服务器利用起来,然后就有了Lisper

插件初始化

插件初始化流程:

  1. 在每个文章底部添加脚本。
  2. 脚本会创建iframe,请求评论页面。
  3. 在评论页面中,请求当前页面的评论并渲染。

在hexo中加入下面的脚本,这个javascript代码主要是保存page(当前页面)、id(用户id)、el(评论插件挂载的dom元素)配置信息。然后在后面的立即执行函数中通过script标签请求https://comment.dowob.cn/js/comment.js这个文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#comments
script(type='text/javascript').
window.commentConfig = {
page: '#{page.path}',
id: #{theme.lisper},
el: document.getElementById('comments')
};
(function() {
var commentScript = document.createElement('script');
commentScript.type = 'text/javascript';
commentScript.async = true;
commentScript.src = 'https://comment.dowob.cn/js/comment.js';
(document.getElementsByTagName('head')[0]||document.getElementsByName('body')[0]).appendChild(commentScript);
})();

comment.js中会创建一个iframe,在这个iframe中加载评论页面,同时使用iframe.contentWindow.postMessage跨域通信,将配置发送过去。因为iframe的内容加载后不会改变iframe窗口的高度,所以主体这边监听iframe发来的高度消息,将主体中iframe的高度进行修改。

github登陆

github登陆,需要在github中创建一个oauth app,这时github会分配client_id、client_secret_id。

当用户点击登陆键后,依次进行下面步骤:

  1. 请求/oauth,服务端会判断用户是否已经登陆,如果没有登陆,重定向到https://github.com/login/oauth/authorize?response_type=code&client_id=${Config.client_id}&redirect_uri=${redirectURI}
  2. 这时候github会判断用户是否已经登陆了github,如果没有,会让用户登陆;如果已经登陆会通知用户是否授权github oauth app获取用户信息,默认是public信息。授权成功后,跳转到redirectURI。
  3. github会重定向到redirectURI,同时带上请求参数code,服务端根据这个code和client_id、client_secret_id来访问https://github.com/login/oauth/access_token?client_id=${Config.client_id}&client_secret=${Config.client_secret_id}&code=${code}
  4. 最后github会返回access_token,之后的访问带上这个access_token就能获取用户信息啦。

这个github登陆卡了我好多天,因为我想实现的效果是用户点击登陆后弹出一个窗口,然后登陆完成后窗口自动关闭,同时原窗口加载用户信息,后面查到方法如下:

  1. 用户的登陆使用let win = window.open('/oauth')来打开新窗口。
  2. 在脚本初始化后,对window监听message事件,如果这个事件是登陆完成(done)那么加载用户信息。
  3. 当用户在新窗口完成登陆后,github重定向/oauth/login?code=3213sad,服务器处理完这个请求后,返回一个blank.ejs
  4. blank.ejs中通过window.opener.postMessage发送请求完成done的信息,评论页面的message事件处理函数便会执行,然后blank.ejs自己关闭。

之所以这么麻烦主要还是因为跨域。

参考

  1. nginx支持https https://liluyang.me/2019/04/03/20190403_HTTPS%20%E9%85%8D%E7%BD%AE%E6%95%99%E7%A8%8B/

  2. nodejs mysql 语句生成器http://knexjs.org/

  3. iframe resize https://github.com/davidjbradshaw/iframe-resizer

  4. 另一个评论插件的实现 http://blog.cgsdream.org/2017/09/21/bye-disqus/