SSE实践(1)

GetProgress 方法深度解析

一、方法概述

GetProgress 是一个基于 Server-Sent Events (SSE) 技术实现的实时进度推送接口,是整个任务进度跟踪系统的核心组件。

核心职责

  • 建立客户端与服务端的长连接
  • 实时监控任务进度变化
  • 增量推送进度更新给前端
  • 任务完成后自动断开连接

二、技术原理

SSE 协议简介

Server-Sent Events 是一种单向实时通信协议:

特性 说明
通信方向 服务端 → 客户端(单向)
连接方式 基于 HTTP 的长连接
数据格式 data: {JSON}\n\n
自动重连 客户端自动尝试重连
兼容性 现代浏览器均支持

与传统轮询的对比

对比项 轮询 (Polling) SSE
请求方式 客户端主动轮询 服务端主动推送
连接状态 短连接,频繁建立 长连接,持续保持
实时性 取决于轮询间隔 实时推送
资源消耗 较高(重复建立连接) 较低(复用连接)

三、核心实现解析

3.1 参数校验与错误处理

csharp 复制代码
[HttpGet("{taskId}/progress")]
public async Task GetProgress(string taskId)
{
    // 任务存在性校验
    if (!_taskService.TaskExists(taskId))
    {
        Response.StatusCode = 404;
        await Response.WriteAsync("任务不存在");
        return;
    }
    // ...
}

设计要点

  • 采用快速失败策略,避免无效的长连接占用资源
  • 直接操作 Response 对象返回错误,无需经过 MVC 管道

3.2 SSE 响应头配置

csharp 复制代码
Response.Headers["Content-Type"] = "text/event-stream";
Response.Headers["Cache-Control"] = "no-cache";
Response.Headers["Connection"] = "keep-alive";

响应头说明

响应头 作用
Content-Type text/event-stream 标识 SSE 流格式
Cache-Control no-cache 禁用缓存,保证实时性
Connection keep-alive 维持长连接状态

3.3 核心循环逻辑

csharp 复制代码
var lastProgress = -1;
var completed = false;

while (!completed)
{
    // 获取最新任务状态
    var task = _taskService.GetTask(taskId);
    if (task == null) break;

    // 增量推送:仅在进度变化时发送
    if (task.Progress != lastProgress)
    {
        lastProgress = task.Progress;
        
        var data = new
        {
            TaskId = task.TaskId,
            Progress = task.Progress,
            Status = task.Status,
            Message = task.Message,
            Result = task.Result
        };

        var json = System.Text.Json.JsonSerializer.Serialize(data);
        await Response.WriteAsync($"data: {json}\n\n");
        await Response.Body.FlushAsync();
    }

    // 任务完成检测
    if (task.Status == "completed" || task.Status == "failed")
    {
        completed = true;
        break;
    }

    // 500ms 轮询间隔
    await Task.Delay(500);
}

执行流程

┌─────────────────────────────────────────────────────────────┐

│ GetProgress 主循环 │

├─────────────────────────────────────────────────────────────┤

│ │

│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │

│ │ 获取任务信息 │───→│ 进度变化检测 │───→│ 增量推送更新 │ │

│ └──────────────┘ └──────────────┘ └──────────────┘ │

│ │ │ │ │

│ ↓ ↓ ↓ │

│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │

│ │ 任务完成检测 │←───│ 延迟500ms │←───│ 刷新响应流 │ │

│ └──────────────┘ └──────────────┘ └──────────────┘ │

│ │ │

│ ↓ │

│ ┌──────────────┐ │

│ │ 退出循环 │ │

│ └──────────────┘ │

│ │

└─────────────────────────────────────────────────────────────┘

3.4 SSE 数据格式

推送的数据结构

字段 类型 说明
TaskId string 任务唯一标识
Progress int 进度百分比 (0-100)
Status string 任务状态
Message string 进度描述信息
Result string 任务结果(完成时)

状态枚举

状态值 含义
pending 任务已创建,等待执行
processing 任务正在执行中
completed 任务执行完成
failed 任务执行失败

实际推送示例

思考过程

GetProgress 方法解读

方法概述

这是一个 SSE (Server-Sent Events) 实时进度推送接口 ,是整个进度跟踪系统的核心方法,允许服务器主动向客户端推送任务进度更新。

技术原理

Server-Sent Events (SSE) 是一种单向的实时通信协议:

  • 客户端发起一次 HTTP 请求建立长连接
  • 服务器通过该连接持续推送事件
  • 无需客户端反复轮询,效率更高

核心流程

代码逐段解析 1. 参数校验与错误处理

  • 首先检查任务是否存在
  • 不存在则直接返回 404 错误 2. SSE 响应头设置
    响应头 作用 Content-Type: text/event-stream 告知客户端这是 SSE 流 Cache-Control: no-cache 禁止缓存,确保实时性 Connection: keep-alive 保持长连接
  1. 核心循环逻辑
    工作流程:

步骤 操作 说明 1 获取任务信息 从 TaskProgressService 获取当前任务状态 2 检测进度变化 只有进度改变时才推送(避免无效推送) 3 构建并发送 SSE 事件 序列化任务数据为 JSON 4 检查任务状态 任务完成或失败时退出循环 5 延迟等待 每 500ms 检查一次

  1. SSE 数据格式

推送的数据格式:

与前端的交互

前端使用 EventSource 连接:

设计亮点

特性 实现方式 优势 增量推送 只在进度变化时推送 减少网络流量 长连接复用 使用 SSE 协议 比轮询更高效 自动断开 任务完成后退出循环 避免资源浪费 低延迟 500ms 检查间隔 平衡性能与实时性

总结

GetProgress 方法是一个 基于 SSE 的实时进度推送端点 ,通过长连接和增量更新机制,实现了高效的服务端主动推送,是前端进度条实时更新的核心技术支撑。

四、前端消费方式

4.1 EventSource 连接

typescript 复制代码
const eventSource = new EventSource('/api/tasks/{taskId}/progress');

eventSource.onmessage = (event) => {
    const data = JSON.parse(event.data);
    updateProgress(data.Progress, data.Message);
};

eventSource.onerror = () => {
    console.error('SSE 连接失败');
    eventSource.close();
};

4.2 生命周期管理

typescript 复制代码
// 组件挂载时建立连接
onMounted(() => {
    eventSource = new EventSource(url);
});

// 组件卸载时关闭连接
onUnmounted(() => {
    eventSource?.close();
});

五、设计亮点与架构考量

5.1 增量推送策略

问题:如果每次循环都推送数据,会造成大量无效网络传输。

解决方案 :通过 lastProgress 变量记录上次推送的进度值,仅在进度变化时才发送数据。

csharp 复制代码
if (task.Progress != lastProgress)
{
    lastProgress = task.Progress;
    // 推送更新...
}

5.2 优雅的连接管理

自动断开机制

csharp 复制代码
if (task.Status == "completed" || task.Status == "failed")
{
    completed = true;
    break;
}

优势

  • 任务完成后自动释放资源
  • 避免僵尸连接占用服务器资源
  • 客户端收到最终状态后可安全关闭连接

5.3 性能优化

优化点 实现方式 效果
减少推送频率 500ms 检查间隔 平衡实时性与性能
增量更新 仅推送变化数据 减少网络流量
对象池复用 TaskProgressService 单例 减少对象创建开销

5.4 线程安全考虑

由于 TaskProgressService 是单例服务,多个请求可能同时访问同一任务数据:

csharp 复制代码
// TaskProgressService 中的更新方法
public void UpdateTask(string taskId, int progress, string status, string message)
{
    if (_tasks.TryGetValue(taskId, out var task))
    {
        task.Progress = progress;
        task.Status = status;
        task.Message = message;
    }
}

六、应用场景与扩展

6.1 适用场景

场景 说明
文件上传进度 实时显示上传百分比
数据处理进度 批量任务执行进度展示
报表生成进度 复杂报表生成状态追踪
长时间任务监控 CI/CD 流水线状态监控

6.2 扩展方向

1. 多任务订阅

  • 支持客户端订阅多个任务
  • 使用 EventSourceevent 字段区分任务

2. 心跳机制

  • 添加定期心跳包检测连接状态
  • 异常断开时自动重连

3. 历史进度查询

  • 保存任务进度历史
  • 支持进度回放功能

4. 权限控制

  • 增加任务访问权限校验
  • 支持任务隔离

七、总结

GetProgress 方法通过 SSE 技术实现了高效的实时进度推送:

核心优势

  1. 低延迟:服务端主动推送,无需客户端轮询
  2. 高效率:增量更新策略,减少网络流量
  3. 高可靠:任务完成自动断开,避免资源泄漏
  4. 易集成:标准 SSE 协议,前端实现简单

技术价值

该方法展示了如何在 ASP.NET Core 中实现轻量级实时通信,为耗时操作提供直观的进度反馈,提升用户体验。


相关推荐
MacroZheng12 小时前
平替Cursor!Claude Code + VSCode = 王炸!
前端·vue.js·人工智能
沄媪12 小时前
XSS 跨站脚本攻击
前端·ctf·xss
Bat U12 小时前
JavaEE|前端集合
前端
问心无愧051312 小时前
ctf show web入门260
android·前端·笔记
之歆12 小时前
Day22_CSS 函数完全指南:从变量到数学计算的现代样式编程
开发语言·前端·javascript·css·tensorflow·less
lichenyang45312 小时前
#鸿蒙基础复盘:生命周期、启动链路、路由跳转与真实需求定位
前端
ZengLiangYi12 小时前
Prompt 工程:让 LLM 输出结构化 JSON
前端·javascript·后端
Asmewill12 小时前
LangGraph学习笔记四(Node和Edge)
前端