EventSource 配置请求头及实现post请求

8,655 阅读4分钟

EventSource

MDN详解:Web API > EventSource

EventSource 基于 HTTP 协议实现,通过与服务器建立一个持续连接,实现了服务器向客户端推送事件数据的功能。在客户端,EventSource 对象通过一个 URL 发起与服务器的连接。连接成功后,服务器可以向客户端发送事件数据。在客户端,通过 EventSource 对象注册事件处理函数,以接收来自服务器的事件数据。

1)EventSource 是一个 Web API,它允许网页通过 HTTP 长连接从 Web 服务器接收实时更新,而无需刷新页面或向服务器发送重复请求。

2)使用 EventSource,网页可以订阅从服务器发送的事件流。一旦建立连接,服务器可以随时向客户端发送事件,客户端可以根据需要进行操作。

3)EventSource 是单向通信的,只能从服务器端向客户端发送数据。

EventSource.readyState 代表SSE连接状态: CONNECTING0)、OPEN1)或 CLOSED2)。注意:使用浏览器提供的本地EventSource服务,无法获取连接状态编码。

使用

项目中常用的是get方式,不需要安装插件,直接创建EventSource对象,通过EventSource对象连接服务,连接服务以后就可以接受服务推送的消息。

// 创建一个EventSource实例对象,传入请求URL
const eventSource = new EventSource('url')
 
// 与事件源的连接刚打开时触发
eventSource.onopen = function (e) {
    console.log(e, '定义相应的回调函数');
};

// 后端返回信息,格式可以和后端协商
eventSource.onmessage = function (e) {
    console.log(e);
    const { data = [] } = JSON.parse(e.data); // 返回字符串格式数据,进行转换
};

// 连接失败(比如连接中断、后端返回错误信息)
eventSource.onerror = function (e) {
    console.log(e);
    eventSource.close(); // 关闭连接
};

EventSourcePolyfill

EventSourcePolyfill 是 EventSource 封装的一个方法,可以配置请求头。

  1. 安装
 npm install event-source-polyfill --save
  1. 引用
import { EventSourcePolyfill } from "event-source-polyfill"
  1. 使用
getRealtimeMessage() {
  const URL = process.env.VUE_APP_BASE_API + '/stream';
  const source = new EventSourcePolyfill(URL, {
    heartbeatTimeout: 5 * 60 * 1000, // 配置请求超时时间
    headers: {
      'Authorization': 'token'
      // ...... 其它请求头信息
    }
  });
  source.onopen = function (res) {
    console.log(res);
  };
  source.onmessage = function (res) {
    const { data = [] } = JSON.parse(res.data);
  };
  source.onerror = function (res) {
    console.log('push message exception');
    source.close();
  };
}

POST 请求

EventSource API 是用于服务器发送事件(SSE)的客户端接口。它不支持发起 POST 请求。如果需要发送数据到服务器以便它能够推送事件给客户端,应该使用标准的 AJAX 请求(例如使用 Fetch API)或者WebSocket。

常用的方式就是借助第三方库的fetchEventSource方法连接服务,通过AbortController 对象可以关闭服务。以下是使用 Fetch API 发送数据到服务器的示例:

  1. 安装fetch-event-source
npm install @microsoft/fetch-event-source
  1. 使用
import { fetchEventSource } from '@microsoft/fetch-event-source';

getRealtimeMessage() {
  const params = {}; 
  const ctrlAbout = new AbortController();
  fetchEventSource('your-server-endpoint', {
    method: 'POST',
    headers: {
      'Authorization': 'token',
      'Content-Type': 'application/json', // 文本返回格式
    },
    body: JSON.stringify(params),
    signal: ctrlAbout.signal,
    openWhenHidden: true, // 在浏览器标签页隐藏时保持与服务器的EventSource连接
    onmessage(res) {
      // 操作流式数据
    },
    onclose(res) {
      // 关闭流
    },
    onerror(error) {
      // 返回流报错
    }
  })
}

手动中断返回

  1. 获取实例:创建一个 AbortController 的实例,用于发送中断信号。
const controller = new AbortController();
const { signal } = controller;
  1. 传递信号:调用 fetchEventSource 时,将 signal 作为参数传递,通过这个信号来控制请求的中断。
fetchEventSource(url, {
  signal: signal,
  // ... 其他配置项
});
  1. 中断请求:调用 AbortController 的 abort 方法。
controller.abort();

调用 abort 方法后,如果返回还在进行中,它将被中断,fetchEventSource 的连接将被关闭。

注意:

AbortController的abort()方法只能调用一次来取消与之关联的活动请求。第一次调用ctrlAbout.abort()时,与该AbortController相关联的AbortSignal的aborted属性会被设置为true,表示请求已经被取消。

如果需要再次取消相同的请求或者启动一个新的请求并有能力取消它,必须创建一个新的AbortController实例:

// 发起一个新的可取消的请求,需要再次创建实例
const newCtrlAbout = new AbortController();
fetchEventSource(url, { signal: newCtrlAbout.signal });
 
// 使用新的控制器来取消新的请求
newCtrlAbout.abort(); 

所以每次想要发起一个新的可取消的请求时,都应该创建一个新的AbortController实例。这样就可以独立地控制每个请求的取消操作。

其他

  1. 提示报错信息:SyntaxError: Unexpected end of JSON input,可能是当前返回的json体和接口的json体不匹配。

  2. web端本地起服务正常,部署到服务器上,无法实现流形式、数据最后一次性返回。应该是nginx默认开启缓存引起的。可以修改nginx的配置文件:

// 定义后端服务器响应的超时时间
proxy_read_timeout 86400s;

// 禁用代理缓冲
proxy_buffering off;

// 禁用代理缓存
proxy_cache_off;

image.png

参考学习