我正在開發一個聊天應用程式。我想知道如何設計用于從服務器獲取訊息的 API。
當應用程式加載聊天視窗時,我使用端點顯示來自服務器的最后 20 條訊息:
/messages?user1={user1Id}&user2={user2Id}&page=0
其次,我允許用戶在用戶使用相同的端點但使用不同的頁面滾動到頂部時加載和顯示以前的訊息 (1)
/messages?user1={user1Id}&user2={user2Id}&page=1
但是當用戶開始互相發送訊息時,這種設計就不能正常作業了。原因是端點使用降序回傳訊息。呼叫端點將在發送/接收訊息之前和之后給出不同的結果集。
我的目標是在用戶滾動瀏覽對話歷史記錄時始終獲得 20 條以前的訊息。
您將如何以簡潔的方式實作這一點(包括 REST API 設計)?我可以想象一些解決方案,但它們對我來說似乎很臟。
uj5u.com熱心網友回復:
REST 不能很好地擴展實時應用程式。一次又一次地打開 HTTP 連接需要太多資源。最好使用 websockets。
至于上面的問題,如果您從最新訊息開始分頁,而不是從第一條訊息開始,那么我不會懷疑它會發生變化。要保留頁面之后,您需要發送您開始使用的訊息 ID。因此,例如:GET ...&count=20&latest=1,在您獲得 20 條訊息串列之后,您將獲得最新訊息的 id 并進行分頁GET ...&count=20&basePoint={messageId}&page=0以始終獲得完全相同的頁面,無論您收到新訊息。之后你繼續GET ...&count=20&basePoint={messageId}&page=1等等......GET ...&count=20&basePoint={messageId}&page=-1如果有更新的訊息,你將有負面頁面。雖然我不知道任何以這種方式使用分頁的聊天應用程式。
我要做的是GET ...&count=20&latest=1獲取第 20 條訊息,然后GET ...&count=20&before={messageId_20th}再從第 40 條串列中獲取最后一條訊息,GET ...&count=20&before={messageId_40th}依此類推。要獲取新訊息,您可以GET ...&count=20&latest=1再次執行或GET ...&count=20&after={messageId_1st}.
如果您在客戶端中使用快取機制,上述方法都不是很好。我會在視頻中添加諸如關鍵幀之類的內容,例如關鍵資訊。例如,每 20 條訊息可以是一個關鍵訊息。我會根據關鍵訊息 id 進行快取,以便回應可以快取,例如GET ...&count=20&latest=1回傳訊息,串列中間的一個將具有keyMessage=true. 我會從最后一個關鍵訊息開始下一個請求,例如GET ...&count=20&before={messageId_lastKey},因此回應將是可快取的。
另一種方法是從第一條訊息開始分頁。因此,當您這樣做時GET ...&count=20&latest=1,它將寫入訊息的索引,例如第 1234 條訊息。您可以像在關鍵訊息解決方案中一樣基于每 20 條訊息進行快取,但是您可以GET ...&count=20&to=1220在客戶端上執行和合并頁面,而不是訊息 ID。或者,如果您真的想保留資料,則GET ...&from=1201&to=1220&before=1215orGET ...&from=1201&to=1220&last=1214或GET ...&from=1201&to=1214等...并使用GET ...&count=20&to=1200or繼續正常分頁GET ...&from=1181&to=1200。
上部固定頁面方法有什么好處,您也可以使用范圍標題。例如GET .../latest,將回傳最后 20 條訊息,其標頭為Content-Range: messages 1215-1234/1234. 之后你可以做GET .../ Range: messages=1201-1214等等GET .../ Range: messages=1181-1200......當總訊息計數在回應中更新時,如果您希望 1245 同時發生變化,您可以使用或Content-Range: messages 1181-1200/1245自動下載新訊息。你也可以對 URI 做同樣的事情,但是如果你有一個像范圍標頭這樣的標準解決方案,最好使用它而不是重新發明輪子。GET .../ Range: messages=1235-1245GET .../ Range: messages=1235-
從這&user1={user1Id}&user2={user2Id}部分開始,我會根據字母對其進行排序,因此在字母順序中總是user1比. 所以這也可以正確快取,而不是在客戶端上,但是您也可以添加服務器端快取,因此如果兩個參與的用戶最近嘗試獲取相同的對話,它將不會再次從資料庫中查詢。另一種方法是添加一個對話 id,它可以是隨機唯一的,也可以由兩個用戶 id 生成,但對于兩個用戶來說它必須始終相同,例如或user2&user1=B&user2=A -> &user1=A&user2=B/conversations/A B/conversations/x23542asda. 我會做后者,因為如果您開始支持與多個用戶的對話,最好有一個專用的對話識別符號。您可以支持的另一件事是在兩個用戶之間進行多個與主題相關的對話,因此您無需/conversations/A B/{topic}在創建新對話之前使用唯一的 id 并搜索對話,因此/conversations?participants[]=A&participants[]=B&topic={topic}會給您一個空串列或一個串列一次談話。這可用于列出單個用戶的報道/conversations?participants[]=A或列出單個用戶在某個主題中的對話/conversations?participants[]=A&topic={topic}。
uj5u.com熱心網友回復:
一般來說,對于“系統設計”的問題,沒有一個正確答案。可以根據其優缺點考慮多種方法。您提到您想要一種干凈的方式來檢索訊息,因此您的期望可能與我的不同。
這是一個讓您入門的簡單方法/想法:
- 在您的資料庫中有一個可用于對訊息進行排序的欄位。它可以是時間戳、a
message_id或其他您想要的東西。讓我們現在稱之為m_id。 - 在您的客戶端上,有一個欄位來跟蹤
m_id客戶端上當前本地可用的最早訊息。這個鍵(我們稱之為earliest_m_id)將用于查詢資料庫,因為您可以簡單地x獲取earliest_m_id. - 這將解決您獲取錯誤訊息的問題。使用分頁將不起作用,因為頁面會隨著訊息的交換而不斷變化。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/504334.html
