websocket是HTML5開始提供的一種在單個TCP鏈接上進行全雙工通信的協議。大多數 Web 應用程序將經過頻繁的異步JavaScript和XML(AJAX)請求實現長輪詢。輪詢的效率低,很是浪費資源。而websocket可以很好的解決相似的問題。經常使用於即時通信、監控等狀況。 在本案例中, 使用egg+typescript做爲後端框架, 使用egg官方封裝的Socket.IO庫。前端使用vue。html
TS下的egg許多設置和文檔有所不一樣, 可是稍稍看一下仍是能理解的。 按照egg的文件規劃,Socket.IO應該獨立的做爲一個文件夾, 內部包含本身的controller和middleware, 而後和其餘頁面共享router配置前端
// router
export default (app: Application) => {
const { controller, router, io } = app;
// Socket.IO會經過io暴露出來, io.of('/')則是命名空間
router.get('/', controller.home.index); // 這個是正常的http請求
io.of('/').route('online', io.controller.nsp.exchange); // 這個就是websocket請求
io.of('/').route('newmsg', io.controller.nsp.newmsg);
io.of('/').route('sendMsg', io.controller.nsp.sendMsg);
};
複製代碼
// config/plugin 這裏是egg開啓插件插件的地方
const plugin: EggPlugin = {
// static: true,
nunjucks: {
enable: true,
package: 'egg-view-nunjucks', // 模板渲染插件
},
io: {
enable: true,
package: 'egg-socket.io', // 官方的封裝的socke插件
},
};
複製代碼
// config/config.default 根據不一樣環境, 配置插件參數
export default (appInfo: EggAppInfo) => {
// ...
config.middleware = [];
// 配置模板引擎
config.view = {
cache: false,
defaultExtension: 'nunjucks',
mapping: {
'.html': 'nunjucks',
},
};
// 配置socket
config.io = {
init: { }, // passed to engine.io
namespace: {
// 命名空間
'/': {
connectionMiddleware: [
'connection', // 這個是鏈接中間件, 只在connection的時候觸發
],
packetMiddleware: [], // 這個會在每次消息的時候觸發
},
'/example': {
connectionMiddleware: [],
packetMiddleware: [],
},
},
};
return config;
};
複製代碼
// app/router
export default (app: Application) => {
const { controller, router, io } = app;
router.get('/', controller.home.index);
// 這裏的sendMsg至關於一個接口, 負責處理客戶端發送的sendMsg事件
// 這個controller是io模塊的controller, 和egg的controller不一樣
io.of('/').route('sendMsg', io.controller.nsp.sendMsg);
};
複製代碼
// app/io/controller
import { Controller } from 'egg';
export default class NspController extends Controller {
public async sendMsg() {
const { ctx, app } = this;
const nsp = app.io.of('/');
const message = ctx.args[0] || {}
// 向客戶端廣播消息, 在客戶端監聽broadcast事件就能夠獲取消息了
nsp.emit('broadcast', message)
}
}
複製代碼
// app/io/middleware/connection
import { Context } from 'egg';
// io模塊的中間件, 在config/config.default裏配置成connectionMiddleware, 只在
connection的時候觸發
export default function robotMiddleware() {
return async (ctx: Context, next: any) => {
const { app } = ctx;
const nsp = app.io.of('/');
// 向客戶端推送online事件
nsp.emit('online', '有新成員加入聊天室了')
await next();
};
}
複製代碼
這樣, 服務器端的邏輯就完成了,接下來經過vue來實現客戶端邏輯vue
// 客戶端 src/utils/io
import io from 'socket.io-client';
// 稍微封裝一下socket.io, 而後暴露出去。
const socket = function ():any {
const _io = io('http://127.0.0.1:7001/');
_io.on('connect', function(){
console.log('連接成功');
});
_io.on('disconnect', function(){
console.log('斷開連級');
});
return _io
}
export default socket
複製代碼
// 客戶端 app/App.vue
export default class Index extends Vue {
// 頭像
user = {
avatar: 'https://f12.baidu.com/it/u=4263977612,1595937908&fm=76'
}
// 消息列表
msgList: Array<string> = []
//發送消息, 觸發sendMsg事件
sendMsg(msg: string):void {
socket.emit('sendMsg', msg)
}
// 頁面加載以後觸發
mounted() {
// 監聽online事件
socket.on('online', (data: string) => {
this.msgList.push(data)
})
// 監聽broadcast事件, 獲取服務器消息
socket.on('broadcast', (data: string) => {
this.msgList.push(data)
})
}
}
複製代碼
socket是基於事件監聽來進行的, 經過on來註冊監聽事件, 經過emit來觸發事件。 經過服務器和客戶端的配合, 就能夠事件即時的消息推送。這篇文章只寫了最簡單功能, 基於socket.io還有分房間, 踢人,身份識別,私聊等功能, 等下篇文章再寫吧。web