当前位置: 首页 > 工具软件 > ws-node-demo > 使用案例 >

express-ws + vue 示例

舒浩邈
2023-12-01

WebSocket 介绍

WebSocket 是一种协议,2008年被首次提出,2011年被广泛应用,并且大部分浏览器均支持此协议。
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。其实现了服务器和浏览器之间互相通信功能,在WebSocket 出现之前,解决实时获取服务端信息,一般使用 轮询 或者 长轮询 方案。这两种方案 无疑都造成了 服务器压力,WebSocket 就是为了解决这种问题而出现的。

WebSocket 优势

WebSocket 能够替代 轮询 方案的优势在哪?

{
	"sendid": 1,
	"content": "hello"
} 

轮询: 每隔固定的时间向服务器发送请求,在一个 http 协议 下的请求中,我们要发送如上的信息给服务端,我们将数据写在 请求体中,但是请求发送的数据不只是这些,远远不止。其包含了一系列的 http 协议下的数据和规则。
长轮询:浏览器发送请求后,一直等待响应,等服务器有了响应结果后,响应给浏览器,再关闭本次请求。这种方案,造成一个请求响应时长过长,并且若运用于浏览器和服务端多次通信,会极大的造成服务器压力。

WebSocket:
1. 实现了服务端主动实时跟浏览器通讯。
2. 浏览器仅需发送一次请求头中的规则和数据,降低了服务器运行的压力。

express-ws

  1. 引入 express-ws 第三方模块,express-ws 模块是对 ws 模块二次封装,使得其能更好的适用于 express 开发的 node 服务。
npm i express-ws
  1. 初始化 express-ws 服务
const express = require("express")
const app = express()
const ws = require("express-ws")
ws(app) // 将 ws 混入到 app中,模块化开发时也可以混入在 Router 对象中

app.listen(2345,()=>{
  console.log("scoket 服务已开启")
})
  1. 添加 websocket API 接口
app.ws("/socket", (ws,req)=>{
  ws.on("close",()=>{ console.log("本次连接已关闭") })
  ws.on("message", (msg)=>{ ws.send(msg) })
})
// 由此便完成了一个最简单的 WebSocket 接口
  1. 增加鉴权
/**
 * TODO: 鉴权思路
 * 1. 用户登录成功后,给其返回一个 token 字符串
 * 2. 前端通过 sec-websocket-protocol 这项子协议 携带 token 访问
 * 3. 通过 用户IP 匹配 token
 */
const tokenCache= [{
	ip: :ffff:10.10.10.10
	tokenArr: ["88888888888888888"]
}] // 在这里我直接通过数组模拟已存在的 token 信息。用户 ip 可通过 req.ip 获取,一个 ip 下可能有多个 token
app.ws("/socket", (ws,req)=>{
  ws.on("close",()=>{ console.log("本次连接已关闭") })
  let islogin = false
  tokenCache.map(ele=>{
    if(ele.ip == req.ip){
      ele.tokenArr.indexOf(req.headers['sec-websocket-protocol']) != -1? islogin = true: ''
    }
    return ele;
  })
  if(!islogin){
    ws.send(JSON.stringify({ code: 1005, message:"身份认证无效或已过期" }))
    ws.close();
    return 
  }
  ws.on("message", (msg)=>{ ws.send(msg) })
})
  1. 指定客户端通讯,当多个 WebScoket 同时连接时,服务端如何指定某个客户端进行通讯呢?
/**
 * TODO: 鉴权思路
 * 1. 对每个 websocket 连接,建立一个标识 sec-websocket-key
 * 2. 指定标识进行通讯
 * 3. 场景,网页版淘宝客服聊天。
 */
var keys = []  // 我在这里自定了一个 连接组,也可以使用 express-ws 模块提供的 getWss 函数

app.ws("/socket", (ws,req)=>{
  ws.on("close",()=>{
    keys = keys.filter(ele=>{
      return ele.key != req.headers['sec-websocket-key']
    })
  })
  let islogin = false
  tokenCache.map(ele=>{
    if(ele.ip == req.ip){
      ele.tokenArr.indexOf(req.headers['sec-websocket-protocol']) != -1? islogin = true: ''
    }
    return ele;
  })
  if(!islogin){
    ws.send(JSON.stringify({ code: 1005, message:"身份认证无效或已过期" }))
    ws.close();
    return 
  }
  else keys.push({ key: req.headers['sec-websocket-key'], ws})
  ws.on("message", (msg)=>{
  	ws.send(JSON.stringify({ code: 1002, message:"服务端已收到消息" }))
  	msg = JSON.parse(msg)
    if(msg.close){ ws.close(); return }
    keys.map(ele=>{
      if(ele.key != req.headers['sec-websocket-key']){
        ele.ws.send(JSON.stringify({ code: 1002, message:"来自其他人的消息" }))
      }
    })
    return ele
  })
})

到此,就实现了一个简化的 WebSocket 服务,前端我这边使用 vue2 版本进行示例。

data(){
    return{
      path:"ws://localhost:2345/socket",
      socket: null
    }
  },
  methods: {
    init(){
      if(typeof(WebSocket) === 'undefined'){ console.error('您的浏览器不支持WebSocket'); return ;}
      // 实例化socket
      this.socket = new WebSocket(this.path,sessionStorage.getItem("kifet"))
      // 监听socket连接
      this.socket.onopen = this.open
      // 监听socket错误信息
      this.socket.onerror = this.error
      // 监听socket消息
      this.socket.onmessage = this.getMessage
    },
    open(){ 
      let parmas = JSON.stringify({ message: "你好服务器" })
      this.socket.send(parmas)
    },
    error(){ console.log("socket连接错误") },
    getMessage(value){ console.log(JSON.parse(value.data)) },
    send() {
      let parmas = JSON.stringify({ sendid: 1 ,content: "价格上能否优惠" })
      this.socket.send(parmas)
    },
    close() {
      let parmas = JSON.stringify({ close: true })
      this.socket.send(parmas)
    },
  },
  destroyed () {
    // 销毁监听
    this.socket.onclose = this.close
  },
  mounted(){
    if(this.socket == null) this.init()
  }

其他使用说明:

  1. ws(app,[serve],[options]) 使用外部 http/s 服务时,可在此传入 参数
  2. ws.readyState 可查看当前连接状态 服务端 和 客户端均可使用 1 连接正常 2 正在关闭 3 已关闭或无法连接
  3. 前端 可以使用 心跳测试 来校验当前连接状态
    上述代码均为 代码片段,demo项目演示地址和源码地址后续会更新在此处
 类似资料: