JavaScript 流式传输数据 SSE (Server-Sent Events)

简介

在调用通义千问的流式接口时,内容是流式的一点点生成的。这里使用的并不是 WebSocket 而是 SSE(Server-Sent Events)

流式响应允许服务器在数据完全生成之前就开始向客户端发送数据。SSE 是一种允许服务器主动向客户端推送更新的技术。与 WebSocket 不同,SSE 只支持单向通信(从服务器到客户端),但它更简单,只需要一个普通的 HTTP 连接。

以下是使用 JavaScript 创建 SSE 的基本步骤:

创建对象:在客户端使用 new EventSource(url) 方法创建一个新的 EventSource 实例,其中 url 参数是事件源的 URL 地址。
监听消息:通过添加事件监听器来接收来自服务器的消息。可以监听的消息类型包括 message、open 和 error。
处理消息:当收到消息时,根据需要处理这些消息,例如更新网页内容。
关闭连接:如果不再需要接收更新,可以通过调用 EventSource 实例的 close() 方法来关闭连接。

下面是一些例子,演示如何使用 JavaScript 来设置 SSE 并监听服务器发送的事件:

HTML页面:

<!DOCTYPE html>
<html>
<head>
  <title>SSE Test</title>
</head>
<body>
  <div id="messages"></div>
  <script>
    const eventSource = new EventSource('/sse');
 
    eventSource.onmessage = function(event) {
      document.getElementById('messages').innerHTML += event.data + '<br>';
    };
  </script>
</body>
</html>

Node.js 服务端

const http = require('http');
 
const server = http.createServer((req, res) => {
  if (req.url === '/sse') {
    // 设置Content-Type头部以及允许跨域
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Access-Control-Allow-Origin', '*');
 
    // 发送一个初始的数据块
    res.write('data: Initial data\n\n');
 
    // 定时发送事件
    setInterval(() => {
      const data = `data: ${new Date().toISOString()}\n\n`;
      res.write(data);
    }, 1000);
 
    // 如果客户端关闭连接,则终止定时器
    req.on('close', () => {
      clearInterval(interval);
    });
  } else {
    res.end('Not Found');
  }
});
 
server.listen(3000, () => {
  console.log('Server is running on http://localhost:3000/sse');
});

使用 Express.js 的例子

const express = require('express');
const app = express();
const port = 3000;
 
app.get('/events', (req, res) => {
  // 设置Content-Type头信息为'text/event-stream'
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
 
  // 每隔一秒发送一次数据
  setInterval(() => {
    const data = `data: ${new Date().toISOString()}\n\n`;
    res.write(data);
  }, 1000);
 
  // 当客户端断开连接时,停止发送事件
  req.on('close', () => {
    console.log('Client disconnected');
    clearInterval(interval);
  });
});
 
app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

使用 PHP 完成 SSE 的例子:

<?php

ini_set('output_buffering', 'off');
while (@ob_end_flush()) {}

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('X-Accel-Buffering: no');

// 开启输出缓冲
ob_start();
while (true) {
    $number = rand(1, 10);
    /**
     * 每条消息由一行或多行字段组成,每个字段组成形式为:字段名: 字段值。
     * 这里用data作为字段名,则前台可通过event.data来获取字段值
     * 字段以行为单位,每行一个(即以 \n 结尾)。
     * 每个消息之间以空行分隔(即最后一个字段以\n\n结尾)。
     * 以冒号开头的行为注释行,会被浏览器忽略。
    **/
    echo "data: $number\n\n";
    //刷新缓冲区
    ob_flush();
    //将输出缓冲区的内容立即发送到客户端
    flush();
    //模拟快速相应
    sleep(1);
}

修改时间 2024-12-17

声明:本站所有文章和图片,如无特殊说明,均为原创发布。商业转载请联系作者获得授权,非商业转载请注明出处。
随机推荐
JavaScript location对象
什么是 XSS 攻击
使用 MySQL 线程池对压力测试的影响
JavaScript Date 类型
WordPress 获取当前主题文件夹的路径
WordPress 修改 RESTful API 的请求和响应
如何使用命令修改 MySQL 数据库名称
Node.js child_process 模块