搭建完整的IM(即時通信)應用(1)

介紹

即時通信應用服務,整套包含服務端管理端客戶端javascript

預計3篇分享:此次是第一篇,項目的總體介紹和實體關係的梳理前端

現已部署上線,客戶端管理端,歡迎體驗vue

能夠註冊客戶端帳號,也可使用初始默認帳號,現有初始帳號說明:java

帳號 密碼 說明
admin 123456 管理端帳號
user 123456 客戶端普通用戶帳號
muteuser 123456 客戶端被禁言用戶帳號
disabled 123456 客戶端被封禁用戶帳號
member1 123456 客戶端普通用戶帳號
member2 123456 客戶端普通用戶帳號
... 123456 客戶端普通用戶帳號
member30 123456 客戶端普通用戶帳號

功能簡介

  1. 註冊,登陸,我的、羣組聊天,我的信息編輯等基礎功能
  2. 申請添加好友和申請入羣
  3. 表情,圖片,視頻,定位信息支持
  4. 聊天會話列表記錄
  5. 消息記錄(微信的消息記錄真實一言難盡)
  6. 支持多點同時登陸
  7. 百度 UNIT 機器人自動回覆(todo)
  8. 管理端,進行角色和權限的管理,羣狀態管理(我也當一回馬化騰)

需求簡介

移動互聯網發展至今,以微信爲首的即時通信服務已經融入了咱們生活中的各個角落,在公司的一些業務中也扮演着重要的角色,對於即時通信咱們公司原來是使用的環信的服務,可是有不少定製化的需求沒法實現,因此後來決定內部開發一個知足定製化需求的即時通信微服務。node

使用socket.io框架是由於當時後端缺人,加上看了一些例子後以爲使用起來真的很方便,並且全平臺支持,因此這個微服務就在前端團隊進行落地實踐,目前效果還不錯。mysql

社區目前這方面的內容比較少或者太簡陋(只有一個公共的聊天室這種)。另外就是在業務開發過程當中被 PM 搞得很難受,因此想脫離一些特有的業務上的東西,實現一個功能簡單五臟俱全的不摻雜公司業務的 IM 應用,包含服務端,管理端和客戶端。客戶端的模仿對象是微信,由於我很熟悉,不用在產品上面思考太多,另外就是試用的人很熟悉,不須要太多的溝通成本。git

框架簡介

要開發一套完整的即時通信服務,須要如下部分:github

  1. 服務端:用來實現基礎的服務接口和數據持久化
  2. 客戶端:完成登陸、聊天等基礎功能,相似微信
  3. 管理端:管理羣組、用戶和角色權限

server

爲企業級框架和應用而生web

選用阿里的 egg.js 框架作支撐,看中的緣由是他們內部大規模的落地和安全方面作得比較好,沒有選擇 nest 的緣由是集成 socket.io 比較麻煩,ORM 選用 sequelize,數據庫是 mysql ,以前一塊兒使用過,上手難度小sql

admin

開箱即用的中臺前端/設計解決方案

選擇 Ant Design Pro 做爲模板開發管理端,選用的緣由是我對 Vue 全家桶比較熟悉,想借着這個機會熟悉下整套 React 生態 的開發流程,感覺下目前國內兩大開發框架的本質區別和異曲同工,Ant Design Pro 已經發布了好幾年了,也的確給中小型企業帶來效率的提高,也正好適合我這的需求。

client

🛠️ Vue.js 開發的標準工具

使用 @vue/cli 搭建 IM 服務的客戶端,一個移動端的 H5 項目,UI 框架使用的有贊 vant,集成了個人開源組件vue-page-stack和黃老師的better-scroll,實現 IM 的基礎功能

實體關係

做爲一個前端工程師,大多數的平常工做是不須要思考實體關係的。可是,就個人實際體驗來看,懂得實體關係能夠幫助咱們更好的理解業務模型。而對產品和業務理解的提高對咱們的幫助是很是大的,能夠在需求評審的時候發現不少不符合邏輯的地方(怎麼又要吐槽產品經理了),這時候能提出來就會主動避免咱們在後續的過程當中進行反覆開發,同時能夠和產品側的同窗造成比較良好的互動(而不是互懟)。下面簡單羅列下比較重要的實體關係:

經過上圖能夠看到 user 是整個關係圖中的核心,下面介紹下各個實體之間的關係:

  1. user 和 user_info(用戶信息) 是一對一的關係
  2. user 和 role(角色)是多對多的關係
  3. role 和 right(權限)是多對多的關係
  4. user 和 apply(申請)是多對多的關係,申請都是涉及到兩個 user(申請人和被申請人)
  5. user 和 group(羣組)是多對多的關係
  6. group 和 conversation(會話) 是一對一的關係
  7. friend 和 conversation(會話) 是一對一的關係
  8. conversation 和 message(消息)是 1 對多的關係
  9. friend(好友關係) 和 user 沒有直接關係,friend 由兩個 user 肯定

下面詳細介紹下會話、角色與權限:

會話

完成一個即時通信應用,須要考慮的第一個事情就是會話,就是咱們微信裏面的對話窗口。思考會話和消息、用戶、羣組之間的關係花費了很多的精力,最終造成如下的基本關係:

  1. 2 個用戶參與的聊天屬於創建了 Friend 關係(互爲好友)
  2. 多個用戶參與的聊天組成了羣組關係
  3. Friend 和會話之間的關係是 1 對 1 的關係,能夠經過 Friend 找到此 Friend 的會話,也能夠經過會話肯定 Friend
  4. 羣組和會話之間的關係是 1 對 1 的關係,能夠經過羣組找到此羣組的會話,也能夠經過會話肯定羣組
  5. 消息屬於某個會話,能夠根據會話查看對應的消息列表
  6. 保存消息的時候更新會話的激活時間,用戶的會話列表根據激活時間排序,也就是最近的會話再最前面

也就是說,用戶和會話沒有直接的關係,只能經過用戶對應的單聊和羣聊去獲取會話,這樣作能夠有如下的好處:

  1. 不管是單聊仍是羣聊,鏈接上的用戶只要 join 進對應的會話 room 裏面就能夠,消息也是在對應的 room 裏面發佈
  2. 不管是單聊仍是羣聊,消息的保存和查詢都比較簡單,都是隻針對這個會話
  3. 獲取我的的會話列表也變得很簡單,用戶的會話列表經過查詢用戶『全部的 Friend 和羣組』->『全部的會話』->『排序會話(根據激活時間)』,就能夠獲取

角色和權限

爲了設計一個靈活、通用、方便的權限管理系統,本系統採用 RBAC(基於角色的訪問控制)控制,來設計一個通用的『用戶角色權限』平臺,方便後期擴展。

RBAC

RBAC(基於角色的訪問控制)是指用戶經過角色與權限進行關聯。即一個用戶擁有若干角色,每個角色擁有若干權限(固然了,別把衝突的角色和權限配在一塊兒)。這樣,就構形成「用戶—角色—權限」的受權模型。在這種模型中,用戶與角色之間、角色與權限之間,通常是多對多的關係。

本系統默認的角色和權限

本系統默認有管理員、通常用戶、禁言用戶和封禁用戶這幾種角色,給不一樣的角色分配不一樣的權限,因此須要針對管理和發言等接口路由作一下統一的鑑權(經過中間件的方式)處理,具體方式和方法在後端項目中會詳細說明。本系統暫時採用預先定義了角色和權限的方式,後續想要擴展的話能夠編輯角色和權限。

管理員

沒見過微信的管理端,可是能夠想象一下,管理員能夠配置用戶的角色和權限,能夠編輯羣組的狀態:

  1. 登陸的權限
  2. 羣組狀態的編輯
  3. 針對用戶的角色和權限的編輯

普通用戶

註冊登陸後,能夠正常的添加好友和加入羣組,能夠修改我的基礎信息和處理申請

  1. 註冊登陸
  2. 編輯我的基礎信息
  3. 添加好友,申請入羣
  4. 處理好友申請和入羣申請
  5. 聊天

禁言用戶

  1. 註冊登陸
  2. 編輯我的基礎信息
  3. 添加好友,申請入羣
  4. 處理好友申請和入羣申請

封禁用戶

沒法登陸

角色的組合

舉個例子:如今有一個新版的我的中心須要上線測試,首先新建一個角色『測試我的中心』,再給這個角色分配對應的權限;而後給普通用戶作個分組,選出一些人配置上這個角色,這樣就能夠進行測試了。

即時通信原理

下面說下即時通信服務的核心通信原理,和通常的 http 服務同樣,有一個服務端和客戶端進行通信,只不過詳細的協議和處理方式不同。

WebSocket

因爲歷史緣由,如今主流的 http 協議是無狀態協議(HTTP2 暫時應用不普遍),通常狀況是由客戶端主動發起請求,而後服務端去響應。那麼爲了實現服務端向客戶端推送信息,就須要前端主動向後端去輪詢,這種方式低效且容易出錯,在以前咱們的管理端首頁確實是這麼作的(5s 一次)。

爲了實現這種服務端主動推送信息的需求, HTML5 開始提供一種在單個 TCP 鏈接上進行全雙工通信的協議,也就是 WebSocket。WebSocket 使得客戶端和服務器之間的數據交換變得更加簡單,容許服務端主動向客戶端推送數據。WebSocket 協議在 2008 年誕生,2011 年成爲國際標準,目前絕大部分瀏覽器都已經支持了。

WebSocket 的用法至關簡單:

var ws = new WebSocket("wss://echo.websocket.org");
 ws.onopen = function(evt) {  console.log("Connection open ...");  ws.send("Hello WebSockets!"); };  ws.onmessage = function(evt) {  console.log( "Received Message: " + evt.data);  ws.close(); };  ws.onclose = function(evt) {  console.log("Connection closed."); }; 複製代碼

有了 WebSocket 協議讓服務端主動推送信息有了先進的武器,那麼有沒有什麼方式能夠兼容新舊瀏覽器呢?其實不少人想到了這點,答案就是socket.io

socket.io

socket.io進一步封裝了WebSocket的接口,並且能夠在舊版本瀏覽器中自主切換到使用輪詢的方式進行通信(咱們使用者是不會感知的),造成了一套統一的接口,大大減輕了開發的負擔。主要具備如下優勢:

  1. 封裝出了一套很是易用的接口,先後端統一,使用很是簡單
  2. 全平臺支持(原生和 H5,微信小程序中也有對應的實現)
  3. 自適應瀏覽器,在比較老的瀏覽器中主動切換使用輪詢的方式,不須要咱們本身搞輪詢

這是 socket.io 主頁

最快,最可靠的即時通信引擎(FEATURING THE FASTEST AND MOST RELIABLE REAL-TIME ENGINE)

使用起來真的很簡單:

var io = require('socket.io')(80);
var cfg = require('./config.json'); var tw = require('node-tweet-stream')(cfg); tw.track('socket.io'); tw.track('javascript'); tw.on('tweet', function(tweet){  io.emit('tweet', tweet); }); 複製代碼

總結

有了以上的基礎,咱們就基本完成了開始寫代碼以前的準備:明確了這個應用的基礎功能和實體之間的關係,也明確了基礎的技術方案選型,劃分了3個項目的各自任務。下面就開始完成 server 端吧

未完待續:下一篇介紹 server 端

相關文章
相關標籤/搜索