「實戰」搭建完整的IM(即時通信)應用(1)

介紹

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

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

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

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

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

<img width="300" src="https://i.loli.net/2020/07/15/fO2naUmPluYRsBd.png">node

功能簡介

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

需求簡介

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

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

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

框架簡介

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

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

server

爲企業級框架和應用而生

選用阿里的 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 的基礎功能

實體關係

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

<img width="600" src="https://i.loli.net/2020/07/14/Zhz85V2ptOylDcj.png">

經過上圖能夠看到 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 端

相關文章
相關標籤/搜索