部落格

如何製作一個類似 Facebook Messenger 的聊天平台

·Huaying Tsai
平台故事
如何製作一個類似 Facebook Messenger 的聊天平台

為了方便平台上用戶們相互聯繫,製作了一個基礎聊天軟體,本篇主要討論的會是架構面及功能上的一些細節。

關於架構

大部分的形況下網站運行的方式只涉及到單向的資料傳遞,不管是直接 請求頁面、或是 ajax 做 get/post/delete… 操作,都是 client 端向 server 提出請求。

如果今天需要做實時的應用像是聊天功能或是通知功能,我們需要 server 能主動通知 client 端。在這情況下最常用的有兩種 — PollingWebSocket

Polling

Polling 顧名思義就是由 client 端持續地的向 server 端發送請求直到有結果為止,很適合在執行時間稍長的任務使用。舉例來說,假設你今天有個問卷網站,可以一次寄 email 邀請五十個人。邀請按鈕點下以後可能需要一分鐘去處理這麼多人的邀請信件寄送,你的網站又想要在任務開始後實時追蹤發信的進度,這情況下 Polling 就是個很適合的策略。 但持續性的向 server 發送請求很消耗支援,因此我們可以用一些方式來減緩資源消耗。常見的像是 exponential backoff , 就是當你當下還拿不到結果或是結果跟前一次一樣,那你就再加長你的 delay 時間。一開始可能每 delay 100ms 送一次請求,之後的每一次請求如果還拿不到結果就把 delay time * 2 直到 timeout。

但以上方法並不適合實時應用。以聊天應用的情況來說,我們得持續的做 polling 向 server 要新的信息,非常消耗資源,但用了 exponetial backoff 又會導致資料更新不及時,所以又有一種方案:Long Polling

\1

Long polling 的概念一樣是不斷的發送請求到 server,但 server 會握著你的請求不放,直到有資料可以回傳或是 timeout。當每次的請求有結果後,client 又會建立新的請求以達到持續連線的效果。這樣的做法就不向一般的 Polling 這麼消耗資源,也保有了資料的即時性。印象中 Facebook 有篇文章寫說他們如何採用 Long Polling 來實現 chat 還是 notification 的功能,有興趣的人能在網上搜一下。

WebSocket

WebSocket 屏除了 http 的協定,不再是一個 request 與一個response 的方式。它的網址為 ws:// 或是 wss:// 開頭,概念就是事先在 client 端與 server 之間建立一個通道,資料可以進行雙向交互,這樣的設計也符合實時應用的需要。

我們的平台用的是 Graphql 的 Subscription,底層就是用 WebSocket 所實現的。

\1

關於功能

功能上我們需要的是簡單的一個朋友列表以及對話欄。 後端資料方面的設計不複雜,比較繁瑣的就是當新訊息進來的時候,除了增加一筆新的 Message 資料外,還要送 data 到相對應的 client 更新朋友列表的已讀狀態與最後則訊息的資料欄。

\1

前端部分相對複雜許多,要考慮的地方像是 Pagination、設定訊息已讀、相近時間訊息的聚合,以及 Scroll 上面的問題等等。

設定訊息已讀的部分,比較 tricky 的點是在收到新訊息的時候,假如你已經在這的對話的頁面,你必須立刻再發個 request 告訴 server 設定已讀,並且前端不能亮小紅點。

時間聚合的點要考慮的是,多近時間內的訊息你要把它聚集在一起?還有不同時間點的時間要如何顯示?比如越近的時間顯示時分,稍遠一點顯示星期幾,再遠點顯示日期之類的。

Scroll 的部分則是需要分辨什麼時候需要自動的 scroll to bottom 什麼時候不需要。 Style 方面則是 Responsive 的部分還有手機瀏覽器的特殊處理,這種輸入欄至底、高度 fixed 的 layout 很容易在手機上有奇怪的行為。

結論

實際實作起來會比說起來的複雜要多,聊天功能牽扯到實時數據更新,比一般的 Web App 要花更多時間,但能實時交流的功能用起來也比較有趣! 最後歡迎試用以及提供意見,第一版可能會有一些沒考慮周全的地方,有問題請聯絡 support@thoth.tw :)

\1