EventSource和WebSocket用法

EventSource和WebSocket用法

介绍

我们已熟知HTTP协议,但该协议只能由客户端发起,从服务端获取想要的数据。本文主要介绍WebSocket和EventSource。

区别 WebSocket EventSource
介绍 又称为SSE(Server-Sent Events)
通信过程 双向连接,支持发送和接收数据 单向连接,只能服务端向客户端发送数据,一个EventSource会对http服务开启一个持久化链接,它发送的事件格式是'text/stream',开启EventSource事件后,它会一直保持开启状态,直到被要求关闭
协议标识符 ws(如果加密,则为wss) ws(如果加密,则为wss)
数据格式 可以发送任何格式的数据,例如文本、二进制数据或JSON 只能发送文本格式的数据
支持程度 一些旧的浏览器不支持 可被广泛使用
应用场景 更适合需要实时双向通信的应用,例如视频会议 更适合需要从服务器获取实时信息的应用,例如股票行情或推送

1、WebSocket

属性

WebSocket.binaryType (非只读):使用二进制的数据类型连接。

WebSocket.bufferedAmount (只读):未发送至服务器的字节数。

WebSocket.extensions (只读):服务器选择的扩展。

WebSocket.protocol (只读):服务器选择的下属协议。

WebSocket.readyState (只读):当前的链接状态。

WebSocket.url (只读):WebSocket 的绝对路径。

vue组件直接使用

上面介绍了属性,此处介绍事件、方法(send、close)、使用示例,也可通过MyWebsocket.addEventListener监听事件(close、open、message、error)。

javascript 复制代码
const url = "ws://localhost:9998/echo" || env.wsapi
const MyWebsocket = new WebSocket()

MyWebsocket.binaryType = 'arraybuffer';
// WebSocket 事件:onOpen、onMessage、onClose、onError、
MyWebsocket.onopen= () => {
 // 连接建立时触发
}
// 可监听事件,使用回调函数,如open、message、close
MyWebsocket.addEventListener("open", function (event) {
  socket.send("Hello Server!");
});
MyWebsocket.onmessage = (e) => {
 // 接收服务端数据时触发
 console.log('e.data---->'. e.data)
 ws.send('Hello Server!');
}
MyWebsocket.onerror = () => {
 // 通信发生错误时触发
}
MyWebsocket.onclose = () => {
  // 连接关闭时触发
}
// WebSocket 方法,在某些情况下主动触发,发送给服务端数据或申请关闭
MyWebsocket.send()
MyWebsocket.close()

单例模式创建webSocket连接

(1)声明socket

文件路径:message/messageSocket.js

javascript 复制代码
export default class MessageSocket {
  
  handleMessage = null // 接收数据后的处理方法,由构建时传入
  // 构造函数
  constructor(callback) {
    callback && (this.handleMessage = callback)
    this.establishWsConn()
  }

  socket = null // websocket对象
  url = `${location.protocol == 'https:' ? 'wss' : 'ws'}://${location.host}/message`
  heartbeatTimer = null // 心跳定时器
  
  // 初始化连接websocket
  establishWsConn = () => {
    this.close()
    this.socket = new WebSocket(this.url)
    this.socket.onopen = this.onopen
    this.socket.onclose = this.onclose
    this.socket.onerror = this.onerror
    this.socket.onmessage = this.onmessage
  }

  // 手动断开连接
  close = () => {
    this.heartbeatTimer && clearInterval(this.heartbeatTimer)
    this.heartbeatTimer = null
    this.socket && this.socket.close()
    this.socket = null
  }

  // 连接成功
  onopen = (e) => {
    console.log('连接成功', e) 
    this.socket.send(JSON.stringify({ msgType: 'heartbeat' }))
    this.keepHeartBeat() // 保持连接
    this.handleMessage && this.handleMessage({
      type: 'onopen'
    })
  }
  
  // 连接关闭
  onclose = () => {
    console.log('连接关闭')
    this.close()
    this.handleMessage && this.handleMessage({
      type: 'onclose'
    })
  }
  
  // 连接失败
  onerror(e) { console.log('失败', e) }

  // 接收数据
  onmessage = e => { 
    const data = JSON.parse(e.data)
    console.log('onmessage', data)
    this.handleMessage({
      type: 'onmessage',
      data
    })
  }
  
  // 保持心跳连接
  keepHeartBeat = () => {
    this.heartbeatTimer = setInterval(() => {
      this.socket.send(JSON.stringify({ msgType: 'heartbeat' }))
    }, 59*1000)
  }
}

(2)组件使用

views/message/index.vue

javascript 复制代码
import MessageSocket from './messageSocket.js'
  mounted() {
    this.getMessageList(); // 获取站内信未读消息
  },
  methods: {
    // 查询未读消息
    async getMessageList() {
      try {
        this.messageList = []
        // 传入回调函数
        new MessageSocket(({ type, data }) => {
          console.log('type-getUnreadMessages',type, data)
          if(type != 'onmessage' || !data) return 
          // 此处根据具体情况进行处理,如下将新数据信息塞入列表前面
           this.messageList.unshift(...data)
        })
      } catch (err) {
        this.$message.error(err.message);
      }
    },
 },

2、EventSource

属性

EventSource.readyState (只读):一个代表连接状态的数字。可能值是 CONNECTING(0)、OPEN(1)或 CLOSED(2)。

EventSource.url (只读):一个表示事件源的 URL 字符串。

EventSource.withCredentials (只读):一个布尔值,表示 EventSource 对象是否使用跨源资源共享(CORS)凭据来实例化(true),或者不使用(false,即默认值)。

get请求

javascript 复制代码
 // 初始化一个实例,传入请求地址URL
 const eventSource = new EventSource('url')
  
  // 与事件源的连接刚打开时触发
  eventSource.onopen = function (e) {
       console.log(e, "连接刚打开时触发");
  };
  // 接收数据
   eventSource.onmessage = function (e) {
     console.log(e);
   };
  // 连接失败
   eventSource.onerror = function (e) {
     console.log(e);
     eventSource.close(); // 关闭连接
  };
 
  // 主动关闭连接
  eventSource.close();   

post请求

借助第三方库的fetchEventSource方法连接服务,通过AbortController 可以关闭服务。

javascript 复制代码
npm install @microsoft/fetch-event-source

通过插件请求EventSource

javascript 复制代码
import { fetchEventSource } from '@microsoft/fetch-event-source';

 fetchEventSource(Url, {
   method: 'POST',
   headers: {
     "Content-Type": 'application/json',
     "Accept": 'text/event-stream'
   },
   body: JSON.stringify(data),
   onmessage(event) {
      console.info(event.data);
      // 在这里操作流式数据
   },
   onclose(ee) {
      // 关闭流
   }
   onerror(error) {
       console.info(error);
       //返回流报错
   }
 })

取消请求。注意:取消过一次后需要再声明一个实例对象ctrlAbout去取消。

javascript 复制代码
// 创建一个新的AbortController实例
const ctrlAbout = new AbortController();
// const { signal } = controller;
// 使用fetchEventSource发起请求,并传入新的AbortSignal
fetchEventSource(url, { signal: ctrlAbout.signal });
 
// 当需要取消请求时执行
ctrlAbout.abort();
 
// 如果需要再次发起请求并保留取消的能力,需要再次创建AbortController
const newCtrlAbout = new AbortController();
fetchEventSource(url, { signal: newCtrlAbout.signal });

// 然后可以使用新的控制器来取消新的请求
newCtrlAbout.abort(); // 对新请求有效
相关推荐
我命由我1234513 分钟前
微信小程序 - 自定义实现分页功能
前端·微信小程序·小程序·前端框架·html·html5·js
技术小齐22 分钟前
网络运维学习笔记 022 HCIA-Datacom新增知识点03园区网典型组网架构及案例实战
运维·网络·学习
程序员黄同学1 小时前
请谈谈 Vue 中的 key 属性的重要性,如何确保列表项的唯一标识?
前端·javascript·vue.js
黄卷青灯771 小时前
抓包工具 wireshark
网络·测试工具·wireshark
繁依Fanyi1 小时前
巧妙实现右键菜单功能,提升用户操作体验
开发语言·前端·javascript·vue.js·uni-app·harmonyos
前端御书房1 小时前
前端防重复请求终极方案:从Loading地狱到精准拦截的架构升级
前端·javascript
web182854825121 小时前
nginx 部署前端vue项目
前端·vue.js·nginx
zy0101011 小时前
HTML标签
前端·css·html
程序员黄同学1 小时前
解释 Vue 中的虚拟 DOM,如何通过 Diff 算法最小化真实 DOM 更新次数?
开发语言·前端·javascript
蓝谷芮济2 小时前
二:前端发送POST请求,后端获取数据
前端