解決Hexo博客中 Disqus 在國內不能訪問的方案

動機

昨天菊霜,多說評論系統(tǒng)正式關閉了。

早在一個月前還在做畢設的時候谆刨,聽聞如此噩耗塘娶,就以在糾結到底遷移到哪個評論系統(tǒng)比較好。

但可惜痊夭,除了多說之外刁岸,國內似乎找不到靠譜點的社會化評論系統(tǒng)。

暢言是搜狐出的評論系統(tǒng)她我,試用了一段時間后就棄坑了虹曙。主要缺點是不支持facebook,twitter番舆,github等任何國外的平臺酝碳,其次評論管理很不方便,因為后臺賬號不能用來評論合蔽,所以在自己網(wǎng)站上評論還得重新注冊击敌,好傻呀是不是。官網(wǎng)的用來管理評論的chrome插件還過期不維護了拴事。

韓國人做的來必力沃斤,試過一下,支持的SNS很全刃宵,但也有問題衡瓶,比如不支持評論導入。而且肉眼望過去牲证,bug比較多哮针。

網(wǎng)易云跟帖適合灌水,對于博客網(wǎng)站并不是很適合坦袍。

友言就不吐槽了十厢。

所以捂齐,轉了一圈蛮放,發(fā)現(xiàn)還是老牌的diqus最靠譜,也不用擔心突然哪一天它也跪了的問題奠宜。

由于眾所周知的原因包颁,disqus在國內不能訪問。但由于disqus提供了API(待會再說明這玩意怎么坑)压真,于是可以通過API來訪問和創(chuàng)建評論娩嚼。

于是半個多月前,就做了一些準備工作滴肿。一是確認了通過API訪問使用disqus的可行性岳悟,二是大概查了一下有沒有現(xiàn)成的輪子。于是找到了fooleap用php為jekyll做的一個代理泼差。

考慮到對php不是很熟悉竿音,如果要改源代碼并在hexo里集成對于我而言有些難度和屎,所以最終打算自己用熟悉的Node.js重新造個輪子,用來為hexo博客做disqus的代理春瞬。

并且,我可以自定義評論的樣式套啤,來深度整合進自己寫的主題aqua宽气,感覺會很贊。

項目地址:Disqus-Proxy
配置說明:Disqus-Proxy-Config

思路

整體流程是這樣的潜沦,在前端頁面上測試disqus加載是否成功萄涯,如果成功則顯示disqus的評論框,反之加載獨立的評論框唆鸡,并將請求發(fā)送給自己在國外的vps涝影,利用vps做反向代理,接收來自客戶端的請求到disqus服務器并再轉發(fā)給客戶端争占。

流程圖大概長這樣:

image.png

于是問題就來了:如何檢測disqus是否能成功加載燃逻?

我們先來看看disqus的通用植入代碼

<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};

(function() { 
var d = document, s = d.createElement('script');
s.src = 'https://yourname.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>                             

可以看到disqus是通過創(chuàng)建script標簽,通過設置src屬性動態(tài)引入腳本的臂痕。因此伯襟,我們可以通過判斷這個腳本在指定時間內加載是否完成來判斷是否載入自制評論框。

這里感謝fooleap在這篇文章里提供的思路握童,下面是我在React.js實現(xiàn)判斷的代碼:

  componentWillMount() {

    const s = document.createElement('script')
    const username = window.disqusProxy.username
    s.src = `https://${username}.disqus.com/embed.js`
    s.async = true
    s.setAttribute('data-timestamp', String(+new Date()))
    s.onload = () => {
      this.setState({disqusLoaded: true})
    }
    s.onerror = () => {
      this.setState({disqusLoaded: false})
      console.log('Failed to load disqus. Load disqus-proxy instead.')
    }

    document.body.appendChild(s)

    setTimeout(async () => {
      if (!this.state.disqusLoaded) {
        const DisqusProxy = await import('./DisqusProxy')
        this.setState({DisqusProxy: DisqusProxy.default})
      }
    }, 3000)
  }

如果在3秒后姆怪,腳本仍然未loaded,那么引入自制的評論框澡绩。

這里利用ES6中動態(tài)import的命令稽揭,通過webpack來分割代碼,使得根據(jù)disqus加載狀況肥卡,決定要不要加載剩余的模塊溪掀,以此減少不必要的腳本載入。

評論框使用了React.js召调,后端用了Node.jsKoa框架膨桥,負責請求轉發(fā)。

配置

  • 一臺國外的VPS服務器

前端配置

在 Hexo 主題 Aqua 中使用 diqus-proxy

Hexo 主題 aqua 已經集成了 disqus-proxy唠叛,可以直接在主題的config.yml里配置只嚣。

# 如果disqus賬號名沒設置 那么disqus_proxy也不會生效
disqus_username: ciqu

disqus_proxy:
  # 下面兩項你需要更改為自己服務器的域名和端口
  server: disqus-proxy.ycwalker.com
  port: 443   #端口號需要與后端設置一致
  # 頭像路徑設置
  default_avatar: /avatars/default-avatar.png
  admin_avatar: /avatars/admin-avatar.jpg
  # 腳本和css路徑通常不需要更改
  script_path: /static/js/main.0d0338ae.js
  css_path: /static/css/main.0603c539.css

所以在這里,通常只需要配置三項就可以了艺沼,分別是

  • disqus 的用戶名稱
  • 你用于代理disqus的VPS服務器地址
  • 你用于代理disqus的端口

對于 aqua 册舞,這些就是disqus-proxy全部前端配置。

在其他 Hexo 主題中使用 diqus-proxy

如果你用其他主題障般,那么前端配置會麻煩一些调鲸。

Hexo主題一般用的渲染引擎有pug(原jade)盛杰,ejsswig等。

如何看hexo的渲染主題是哪一個藐石? 進入主題目錄下的layout目錄即供,看文件的格式就知道了。

下面我會一一說明配置方法于微。

模板引擎pug(jade)

進入hexo的主題目錄逗嫡,找到layout文件夾。

通常來說株依,評論會單獨寫成一個文件驱证,比如comment.pug,在layout文件夾下面或者其子目錄下面。

在這個comment.pug中恋腕,hexo在生成(hexo g)時抹锄,會對每一篇生成的文章調用這個文件進行渲染。

在渲染的過程中荠藤,hexo會提供page這個全局變量伙单,在pug文件中,你可以在生成的script中以#{page}調用商源。

comment.pug全部替換成如下內容(注意縮進):

div#disqus_thread
div#disqus_proxy_thread
script.
  window.disqusProxy = {
    username: 'ciqu',
    server: 'disqus-proxy.ycwalker.com',
    port: 5509,
    defaultAvatar: '/avatars/default-avatar.png',
    adminAvatar: '/avatars/admin-avatar.jpg',
    identifier: "#{page.path}"
  };
  window.disqus_config = function () {
    this.page.url = "#{page.permalink}"
    this.page.identifier = "#{page.path}"
  };
  var s = document.createElement('script');
  s.src = '/static/js/main.56688539.js';
  s.async = true;
  document.body.appendChild(s);
  
link(rel="stylesheet" href="/static/css/main.0603c539.css")

這個文件將會渲染出這樣的結果

<div id="disqus_thread"></div>
<div id="disqus_proxy_thread"></div>
<script>
window.disqusProxy = {
    username: 'ciqu',
    server: 'disqus-proxy.ycwalker.com',
    port: 5509,
    defaultAvatar: '/avatars/default-avatar.png',
    adminAvatar: '/avatars/admin-avatar.jpg',
    identifier: "2017/05/25/have-a-nice-weekend/"
};
window.disqus_config = function() {
    this.page.url = "http://ycwalker.com/2017/05/25/have-a-nice-weekend/"
    this.page.identifier = "2017/06/01/diqus-proxy-config/"
}
;
var s = document.createElement('script');
s.src = '/static/js/main.56688539.js';
s.async = true;
document.body.appendChild(s);
</script>
<link rel="stylesheet" href="/static/css/main.0603c539.css">

其中window.disqusProxy對象是自制的評論框參數(shù)车份,參數(shù)說明如下:

  • userName是disqus賬戶名
    • server是你啟用disqus代理的VPS的域名
    • port是VPS服務器啟用disqus代理的端口,需要和后端設置的端口一致
    • defaultAvataradminAvatar分別是默認頭像和管理員頭像
    • identifier是告訴disqus該文章對應評論的標識符牡彻,一般以文章的路徑做標識符扫沼。

其中window.disqus_config是disqus成功加載后,disqus用到的參數(shù)庄吼,分別是文章的地址和標識符缎除。

模板引擎swig

對于渲染引擎為swighexo主題,可以將類似comment.swig直接改成這樣

{% if true %}
  <div id="disqus_proxy_thread"></div>
  <div id="disqus_thread">
  <script type="text/javascript">
        window.disqusProxy = {
          username: 'ciqu',
          server: 'disqus-proxy.ycwalker.com',
          port: 5509,
          defaultAvatar: '/avatars/default-avatar.png',
          adminAvatar: '/avatars/admin-avatar.jpg',
          identifier: '{{ page.path }}'
        };
        window.disqus_config = function () {
          this.page.url = '{{ page.permalink }}';
          this.page.identifier = '{{ page.path }}';
        };
        var s = document.createElement('script');
        s.src = '/static/js/main.0d0338ae.js';
        s.async = true;
        document.body.appendChild(s);
    </script>
    <link rel="stylesheet" href="/static/css/main.0603c539.css">
{% endif %}

比如著名的hexo主題next就用了swig做模板引擎总寻,你只要將其主題下的next/layout/_partial目錄下的comments.swig內容全部替換成上面的代碼就OK了器罐。
注意,window.disqusProxywindow.disqus_config的配置項請參閱前文pug部分的說明渐行。

模板引擎ejs

對于渲染引擎為ejshexo主題轰坊,可以將類似comment.ejs直接改成這樣:

  <div id="disqus_proxy_thread"></div>

  <div id="disqus_thread"></div>
  
  <script>
    window.disqusProxy = {
      username: 'ciqu',
      server: 'disqus-proxy.ycwalker.com',
      port: 5509,
      defaultAvatar: '/avatars/default-avatar.png',
      adminAvatar: '/avatars/admin-avatar.jpg',
      identifier: '<%= page.path %>'
    };
    window.disqus_config = function () {
      this.page.url = '<%= page.permalink %>';
      this.page.identifier = '<%= page.path %>';
    };
    var s = document.createElement('script');
    s.src = '/static/js/main.0d0338ae.js';
    s.async = true;
    document.body.appendChild(s);
  </script>

  <link rel="stylesheet" href="/static/css/main.0603c539.css">

比如使用ejs為模板引擎的fexo主題,可以直接將fexo/layout/_partial/component/目錄下的comments.ejs全部改為上述文件就行了祟印。注意肴沫,window.disqusProxywindow.disqus_config的配置項請參閱前文pug部分的說明。

劃重點:

下載或者克隆項目代碼 disqus-proxy

復制disqus-porxy中已經build完畢的disqus-proxy/build目錄下的static文件夾和avatars文件夾到主題目錄的source文件夾下蕴忆。

static/js/下的以main開頭js文件名替換上面代碼中的s.src = '/static/js/main.56688539.js';文件名颤芬。

static/css/目錄下的css文件名替換link(rel="stylesheet" href="/static/css/main.0603c539.css")中的文件名。

PS:你會發(fā)現(xiàn)static/js/目錄下有兩個js文件,其中main開頭的腳本用于檢測網(wǎng)絡狀況以選擇性加載disqus站蝠,另一個js文件為自制的評論框汰具,在disqus不能加載時會被之前的js文件動態(tài)請求加載,所以不用管它菱魔,你只要確認它的路徑在/static/js/下就可以了留荔。

至此,前端部分配置完成澜倦。

后端配置

后端用了Node.js存谎,由于采用了Koa框架和async/await語法,所以需要Node.js版本7.6以上肥隆,話說端午節(jié)后Node.js最新版本都到8了耶。

在服務器上clone代碼:

git clone https://github.com/ciqulover/disqus-proxy

安裝依賴

只需要安裝后端的依賴

npm i --production
// 或者
yarn install --production

配置server目錄下的config.js

module.exports = {
  // 服務端端口稚失,需要與disqus-proxy前端設置一致
  port: 5509,

  // 你的diqus secret key
  api_secret: 'your secret key',

  // 你的disqus名稱
  username:'ciqu',

  // 服務端socks5代理轉發(fā)栋艳,便于在本地測試,生產環(huán)境通常為null
  socks5Proxy: null,
  // 日志輸出位置,輸出到文件或控制臺 'file' | 'console'
  log: 'console'
}

獲取api-secret

api-secret需要你在disqus的官方網(wǎng)站上開啟API權限句各,申請成功后會得到這個秘鑰吸占。

并且需要在后臺的Settings => Community里開啟訪客評論

image.png

啟動

cd server
node index.js

推薦用pm2在生產環(huán)境啟動,否則你斷開ssh凿宾,node進程就終止了

npm i pm2 -g
pm2 start index.js

如果你在配置文件中選擇log類型為file, 那么輸出的日志文件將在默認為server目錄下的disqus-proxy.log

Done !

關于disqus的API

雖然disqus提供了豐富的API矾屯,和界面友好的文檔,但應用起來是有很多問題的初厚。

首先件蚕,在服務端發(fā)通過API發(fā)送匿名評論是一個非官方支持的API,下面是之前咨詢這個問題時官方的答復郵件:

image.png

所以产禾,通過這個API創(chuàng)建匿名評論時排作,并不能傳遞IP地址的參數(shù),因為disqus在拿到評論時會自動以請求的IP地址作為評論的IP地址亚情。換句話說妄痪,通過后端API創(chuàng)建評論的IP是固定的。就是VPS的地址楞件。

為了解決這個問題衫生,可以拿到disqus用戶的token之后調用API評論。但這很不現(xiàn)實土浸。如果通過OAuth 2罪针,需要跳轉登錄,但一是用戶可能還沒注冊disqus請求匿名評論栅迄,二是既然能跳轉disqus登錄站故,還需要代理個毛線啊。

并且,由于disqus并沒有提供admin賬號的登錄API西篓,所以無法在服務端拿到moderator用戶的cookie愈腾,所以不能直接審核通過匿名評論,而需要在匿名評論發(fā)布后岂津,admin登錄到控制臺審核通過評論虱黄。

由于不能指定評論的IP,并且評論的IP地址只能是VPS主機的IP吮成,所以導致點贊等功能是無法通過后端API來搞的橱乱。

對于https網(wǎng)站

由于我的網(wǎng)站是位于github上的靜態(tài)的https網(wǎng)站,所以在向我的VPS服務器發(fā)送http的XHR請求時就出了問題粱甫。通常來說泳叠,VPS主機是沒有證書的,所以在不購買或者不用自簽名正式的情況下是不能啟用https的茶宵。然而危纫,在https網(wǎng)站發(fā)送請求http會被瀏覽器無情的block掉。

這里我的解決方案是又拍云乌庶。

又拍云提供了源站回源的功能种蝶,目的是緩存源站的靜態(tài)文件。于是瞒大,我就想到了使用又拍云對前端頁面https請求的目標地址進行http回源螃征,這樣相當于在前端頁面與VPS再加了一層代理,前端頁面的https請求通過又拍云以http協(xié)議請求到VPS服務器透敌,得到結果后返回前端頁面盯滚。這就相當于在前端頁面與disqus服務器間架設了兩層代理。

所以這樣就相當于以https訪問又拍云拙泽,再以又拍云以http協(xié)議訪問VPS淌山。只要在這里不設置緩存就行了。

這會不會導致速度減慢呢顾瞻?其實泼疑,國內直連國外的VPS主機到并不一定比連接又拍云后再由又拍云連接VPS速度快。畢竟又拍云的各個主機通常位于主干網(wǎng)絡上荷荤,兩邊的訪問都會很快退渗,相當于一個網(wǎng)游加速器了。

Over.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末蕴纳,一起剝皮案震驚了整個濱河市会油,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌古毛,老刑警劉巖翻翩,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件都许,死亡現(xiàn)場離奇詭異,居然都是意外死亡嫂冻,警方通過查閱死者的電腦和手機胶征,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來桨仿,“玉大人睛低,你說我怎么就攤上這事》” “怎么了钱雷?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吹零。 經常有香客問我罩抗,道長,這世上最難降的妖魔是什么灿椅? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任澄暮,我火速辦了婚禮,結果婚禮上阱扬,老公的妹妹穿的比我還像新娘。我一直安慰自己伸辟,他們只是感情好,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布信夫。 她就那樣靜靜地躺著窃蹋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪静稻。 梳的紋絲不亂的頭發(fā)上警没,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音振湾,去河邊找鬼杀迹。 笑死,一個胖子當著我的面吹牛押搪,可吹牛的內容都是我干的树酪。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼大州,長吁一口氣:“原來是場噩夢啊……” “哼续语!你這毒婦竟也來了?” 一聲冷哼從身側響起厦画,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤疮茄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體力试,經...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡徙邻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了懂版。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鹃栽。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖躯畴,靈堂內的尸體忽然破棺而出民鼓,到底是詐尸還是另有隱情,我是刑警寧澤蓬抄,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布丰嘉,位于F島的核電站,受9級特大地震影響嚷缭,放射性物質發(fā)生泄漏饮亏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一阅爽、第九天 我趴在偏房一處隱蔽的房頂上張望路幸。 院中可真熱鬧,春花似錦付翁、人聲如沸简肴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽砰识。三九已至,卻和暖如春佣渴,著一層夾襖步出監(jiān)牢的瞬間辫狼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工辛润, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留膨处,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓砂竖,卻偏偏與公主長得像灵迫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子晦溪,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內容