知乎的 comet 實現機制是怎樣的?
long-poll 還是 streaming?具體實現細節是怎樣的?
稍微補充一下,Chrome下使用的是JSONP Long Polling(究竟起什麼名字別計較),其他瀏覽器沒去看。
所謂JSONP,就是生成一個script標籤,把回調函數的名稱作為HTTP請求的參數。伺服器解析回調函數名,返回類似callback(data)的代碼,使瀏覽器可以跨域執行非同步請求。
至於知乎想跨域執行的原因,估計是想讓專門的伺服器來處理事件更新,並減少cookie的傳輸量吧。
而Long Polling是說伺服器在接收到這個請求後,阻塞而不立刻返回。如果有新的事件,或者達到超時時間(知乎目前設為30秒),再響應這個請求。
客戶端接收到響應後,再發起一個新的請求。這比輪詢節省了無謂的開銷,但要在伺服器端保持大量長連接(Tornado正好擅長這個)。想效率更高的話可以使用streaming,也就是在使用HTTP長連接的同時,將Transfer-Encoding設為chunked。當伺服器有新的事件時,就發送響應,但不關閉連接。
客戶端接收到響應後,處理該響應,也不關閉連接。伺服器想再次發送響應時,直接使用現有的連接即可。這比Long Polling節省了多次建立和關閉連接的過程,也不用擔心重建連接時錯過新事件(如果你沒在伺服器端保存的話)。但因為是單向的,就需要客戶端每隔一段時間發送心跳包,以證明客戶端還在線。此外,這種方式明顯不能用JSONP實現,因為script標籤在全部載入完前是不會執行裡面的代碼的,因此一次HTTP請求,只有一次執行機會。還想高效就用WebSocket吧。它仍然以HTTP作為傳輸層,在建立連接時,客戶端發起WebSocket握手請求,其頭部內容沿用HTTP協議的定義;伺服器接到請求後,返回驗證信息,並用101狀態碼提示切換到WebSocket協議。這樣一個WebSocket連接就建立好了。後續發送數據時,就不需要帶HTTP請求頭了。
它是雙向的,因此伺服器和客戶端都能隨時發送數據,且發送完不需要斷開連接。任意一方主動斷開連接時,對方都會收到onclose事件(伺服器端的API就自己實現吧);當然你也能直接用這個連接來發送心跳包,協議里還為此預留了2個操作碼(不過暫時沒有瀏覽器端的JavaScript API)。並且,WebSocket也是能跨域的,所以從功能和性能上來說,它都足夠優秀了。缺點就是低端的瀏覽器不支持,例如IE 6~IE 9。當然,支持WebSocket的Web伺服器也比較少(Tornado表示無壓力)。另外,WebSocket的協議版本很多,各種瀏覽器支持的版本不一樣:https://en.wikipedia.org/wiki/WebSocket#Browser_support。例如iOS設備支持的hixie-76就是已被擯棄的,所以實現時還得考慮向下兼容的問題。類似的還能通過Flash 、Silverlight和Java applet等瀏覽器插件來建立socket連接。缺點是沒裝插件就用不了,例如iOS設備支持WebSocket,但不支持後三者。
確切地說,應該是 callback-poll(謝 @葛亮 指教)
把昨天寫的一個答案搬過來了(已修正)——打開 Firebug,發現知乎頁面會不斷產生一個 Net 請求:
http://comet.zhihu.com/update?loc=http%3A%2F%2Fwww.zhihu.com%2Fchannel=。。。callback=。。。
而它得到的 Response 內容顯然就是「新動態」、「新通知」所需要作內容更新的 DOM 數據。繼續挖掘,發現 body 內的第一個元素就是 &