首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Webman 在控制器中完成 SSE 实时流式输出

Webman 在控制器中完成 SSE 实时流式输出

作者头像
Tinywan
发布2026-07-01 13:18:57
发布2026-07-01 13:18:57
1080
举报
文章被收录于专栏:开源技术小栈开源技术小栈

引言

大家好,我是Tinywan。今天我们来聊一聊 SSE(Server-Sent Events,服务器发送事件),这是一种非常适合实时数据推送的技术。与 WebSocket 不同,SSE 只支持服务器到客户端的单向通信。

SSE 的核心是建立一个持久化的 HTTP 长连接,让服务器可以随时向客户端推送数据,而无需客户端频繁发起请求。它是一种 “服务器到客户端” 的单向通信模式,与 WebSocket 的双向通信形成互补。

其优势在于原生支持自动重连、API 简单(EventSource接口)、服务器实现成本低,适合无需客户端回传数据的场景。与 WebSocket 相比,SSE 更专注于单向推送,实现和维护成本更低,是实时通知、日志展示等场景的理想选择。

服务和客户端

本质上,它采用流式方法实现,客户端向服务器发起连接请求并保持连接打开。然后服务器主动向客户端推送消息。使用服务器发送事件(SSE)从服务器发送到客户端的数据必须是 UTF-8 编码的,返回的内容类型是 text/event-stream

例如,在使用 ChatGPT 时,当你向它提问时,你会看到它逐字显示答案。实际上,ChatGPT 在计算的同时主动“推送”预计算数据给你,利用 SSE 技术边计算边返回数据,从而避免了可能导致直接页面关闭的长时间接口等待。

关键特性

  • 单向通信:仅支持服务器向客户端推送数据,客户端无法通过 SSE 向服务器发送数据(需配合 HTTP 或 WebSocket 实现双向交互)
  • 长连接:一次连接建立后持续保持,避免短连接的反复握手开销;
  • 自动重连:连接意外断开时,客户端会自动重试连接(默认间隔 3 秒);
  • 文本流:数据以 UTF-8 文本流格式传输,二进制数据需编码后发送。

代码示例

这里客户端代码为了解决访问跨域问题,直接使用webman视图完成客户端页面。模板是使用的:think-template

如何使用可以看这里哦!

https://www.workerman.net/doc/webman/view.html

服务端

代码语言:javascript
复制
<?php
/**
 * @desc 控制器中使用SSE
 * @author Tinywan(ShaoBo Wan)
 */
declare(strict_types=1);

namespace app\controller;

use support\Request;
use support\Response;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\ServerSentEvents;
use Workerman\Timer;

class StreamController
{
    /**
     * @desc client
     * @param Request $request
     * @return Response
     * @author Tinywan(ShaoBo Wan)
     */
    publicfunction client(Request $request): Response
    {
        return view('stream/client', ['name' => '开源技术小栈']);
    }

    /**
     * @desc server
     * @param Request $request
     * @return Response
     * @author Tinywan(ShaoBo Wan)
     */
    publicfunction server(Request $request): Response
    {
        $connection = $request->connection;
        $id = Timer::add(1, function () use ($connection, &$id) {
            if ($connection->getStatus() !== TcpConnection::STATUS_ESTABLISHED) {
                Timer::del($id);
            }
            $connection->send(new ServerSentEvents([
                'event' => 'message',
                'data' => date('Y-m-d H:i:s').' 服务端发送数据',
                'id' => 2026
            ]));
        });
        $header = [
            'Content-Type' => 'text/event-stream',
            'Cache-Control' => 'no-cache',
            'Connection' => 'keep-alive',
        ];
        return response('', 200, $header);
    }
}

Step1. 必须设置的 HTTP 响应头

代码语言:javascript
复制
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

可选但强烈推荐:

代码语言:javascript
复制
X-Accel-Buffering: no          # 关闭 Nginx 等代理的缓冲(非常重要)

Step2. SSE 消息的基本格式规则

每条消息由若干字段组成,每个字段独占一行,字段之间用换行符分隔,整条消息以两个连续换行符(\n\n)结束。

字段写法

作用说明

是否必须

示例

客户端如何获取

data:

消息正文内容(最核心字段)

必须

data: {"text": "Hello"}\n

event.data

event:

自定义事件类型(不写默认为 message)

可选

event: token\n

addEventListener('token', ...)

id:

消息唯一标识,用于断线重连续传

推荐

id: 12345\n

event.lastEventId

retry:

建议客户端重连间隔(毫秒),断开后客户端会参考此值自动重连

可选

retry: 5000\n

自动处理

: (冒号+空格)

注释行,客户端会完全忽略,常用于调试、心跳、日志

可选

: 这是一条调试信息\n

忽略

Step3. 数据推送:基于规范的文本流格式

服务器通过 HTTP 长连接持续向客户端发送 “事件”,每个事件需遵循严格的文本格式,以\n\n作为结束符。

格式 1:默认事件(客户端通过 onmessage 接收)

代码语言:javascript
复制
data: 您有一条新消息\n
data: 内容:Hello World\n\n  # 多行 data 会合并为一条消息

格式 2:自定义事件名(客户端通过 addEventListener 接收)

代码语言:javascript
复制
event: orderStatus  # 事件名(如“订单状态更新”)
id: 10086           # 事件 ID(用于重连时定位断点)
data: 订单已发货\n\n

格式 3:心跳保活(客户端忽略,仅维持连接)

代码语言:javascript
复制
: 这是注释,无实际数据,防止长连接超时\n\n

客户端

客户端请求

代码语言:javascript
复制
// 客户端创建 SSE 连接(仅支持 GET 方法)
const sse = new EventSource('/service/stream');

浏览器会自动发送 HTTP 请求,携带特殊头信息(如:Accept: text/event-stream)。

全部伪代码

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>客户端 SSE 输出</title>
    <style>
        body {
            font-family: system-ui, sans-serif;
            margin: 20px;
            background: #fafafa;
        }
        #output {
            white-space: pre-wrap;
            word-wrap: break-word;
            background: white;
            border: 1px solid #ddd;
            padding: 16px;
            min-height: 80px;
            line-height: 1.5;
            font-family: Consolas, "Courier New", monospace;
            overflow-y: auto;
        }
    </style>
</head>
<body>

<h3>客户端 SSE 输出</h3>
<div id="output"> SSE 连接中...</div>

<script>
    const output = document.getElementById('output');

    const es = new EventSource('http://127.0.0.1:8787/stream/server');

    es.onmessage = function(e) {
        output.textContent += e.data + '\n';
        output.scrollTop = output.scrollHeight;
    };

    es.onopen = function() {
        output.textContent = '';  // 清空“连接中...”文字
    };
</script>

</body>
</html>

客户端:http://127.0.0.1:8787/stream/client

输出页面内容如下所示:

SSE 典型应用场景

SSE 最适合服务器主动、单向、实时推送数据的场景,尤其在不需要客户端频繁上行实现简单资源占用低的情况下表现出色。以下是主要实际应用场景:

  • AI 智能助手 / 大模型流式生成 支持“打字机”效果,逐 token / 逐句实时输出回答,显著降低用户感知等待时间,提升交互自然感和沉浸感。典型如 ChatGPT、DeepSeek、Claude 等产品的流式回复界面。
  • 实时通知与消息提醒 用于推送新评论、点赞、私信、系统公告、好友在线状态等即时通知。服务器在事件发生时立即推送,避免客户端轮询浪费资源。常见于社交平台、论坛、电商订单状态更新。
  • 任务执行日志与进度实时展示 后端任务(如模型训练、文件处理、部署、CI/CD 流水线、数据导入)的日志或进度,按行或按块实时追加到前端。用户看到类似终端 tail -f 的追随效果,常用于运维后台、开发工具、训练平台。
  • 实时新闻 / 资讯 / 内容 feed 推送突发新闻、热点更新、推荐内容。服务器有新资讯时立即广播给订阅用户,适合新闻客户端、聚合阅读器、社区动态墙。
  • 股票 / 加密货币 / 金融行情实时更新 推送最新股价、K 线增量、指数变动、外汇汇率等。客户端无需轮询,每秒或每变动推送一次,适用于交易终端、行情看板、投资 App。
  • 服务器 / 应用监控仪表盘 实时展示 CPU、内存、磁盘、网络流量、QPS、错误率等指标,每几秒推送一次最新数值或时间序列点,用于绘制曲线图或警报触发。常见于运维监控系统、Prometheus + Grafana 风格的实时面板。
  • 多人在线协作状态同步 在线文档、白板、表格、代码编辑器中推送“他人正在编辑”“光标位置”“内容变更”等提示。服务器广播操作状态给所有协作者,实现低延迟协同感知。
  • 直播 / 赛事比分 / 位置跟踪 推送比分变化、直播弹幕增量、司机/骑手实时位置更新、比赛事件(如进球、犯规)。适合读-only 的实时数据流场景,如体育 App、外卖地图。

SSE 特别适用的业务特征

  • 数据方向:服务器 → 客户端 单向推送(客户端基本只订阅,不需频繁发送)
  • 更新频率:中低频(事件驱动,或每几秒~几十秒一次)
  • 数据体量:单次推送较小(几字节~几 KB 的文本/JSON)
  • 连接时长:较长(分钟~数小时)
  • 对可靠性要求:中等(丢失个别监控点或通知通常可接受)
  • 开发复杂度偏好:希望比 WebSocket 更简单、直接用 HTTP 协议
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-01-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 服务和客户端
  • 关键特性
  • 代码示例
    • 服务端
    • 客户端
  • SSE 典型应用场景
  • SSE 特别适用的业务特征
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档