Server-Sent Events(SSE)是一种基于HTTP的服务器向客户端单向推送事件的技术,非常适合在XML文件处理这类耗时操作中,实时向客户端推送处理进度信息,让用户可以直观看到当前处理状态。

SSE基础原理
SSE的核心是服务端通过保持一个长HTTP连接,持续向客户端发送符合特定格式的事件流数据。每个事件通常包含事件类型、数据和可选的ID,客户端通过EventSource API来监听这些事件,不需要反复发起请求。
SSE的事件流格式要求每条消息以data:开头,消息结束需要加两个换行符,例如:
data: 处理进度10% data: 处理进度20%
XML文件处理进度拆分思路
要实现进度通知,首先需要把XML文件的处理过程拆分成多个可量化的步骤,常见的拆分方式有以下几种:
- 按文件读取比例拆分:先读取XML文件的总大小,处理过程中实时计算已处理的字节数,计算百分比作为进度
- 按节点处理数量拆分:如果XML是结构化的节点数据,统计总节点数,每处理一个节点更新一次进度
- 按处理阶段拆分:把处理过程分为解析、校验、转换、存储等阶段,每个阶段完成推送对应进度
后端实现示例(Node.js)
以下是使用Node.js的Express框架实现SSE推送XML处理进度的示例代码:
const express = require('express');
const fs = require('fs');
const xml2js = require('xml2js');
const app = express();
// 处理XML文件的接口,返回SSE流
app.get('/process-xml', (req, res) => {
// 设置SSE相关的响应头
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// 模拟XML文件路径,实际场景可以从请求参数获取
const xmlFilePath = './test.xml';
// 先获取XML文件总大小,用于计算读取进度
const fileStats = fs.statSync(xmlFilePath);
const totalSize = fileStats.size;
let processedSize = 0;
// 推送初始进度
res.write(`data: ${JSON.stringify({ progress: 0, status: '开始处理XML文件' })}nn`);
// 创建文件读取流,按块处理XML内容
const readStream = fs.createReadStream(xmlFilePath, { highWaterMark: 1024 });
let xmlContent = '';
readStream.on('data', (chunk) => {
processedSize += chunk.length;
xmlContent += chunk.toString();
// 计算当前读取进度
const readProgress = Math.floor((processedSize / totalSize) * 50);
// 推送读取进度
res.write(`data: ${JSON.stringify({ progress: readProgress, status: '正在读取XML文件内容' })}nn`);
});
readStream.on('end', () => {
// 读取完成后,开始解析XML,推送解析进度
res.write(`data: ${JSON.stringify({ progress: 60, status: '开始解析XML内容' })}nn`);
const parser = new xml2js.Parser();
parser.parseString(xmlContent, (err, result) => {
if (err) {
res.write(`data: ${JSON.stringify({ progress: -1, status: 'XML解析失败', error: err.message })}nn`);
res.end();
return;
}
// 解析完成,推送后续处理进度
res.write(`data: ${JSON.stringify({ progress: 80, status: 'XML解析完成,开始处理数据' })}nn`);
// 模拟后续数据处理逻辑
setTimeout(() => {
res.write(`data: ${JSON.stringify({ progress: 100, status: 'XML文件处理完成' })}nn`);
res.end();
}, 1000);
});
});
readStream.on('error', (err) => {
res.write(`data: ${JSON.stringify({ progress: -1, status: '文件读取失败', error: err.message })}nn`);
res.end();
});
});
app.listen(3000, () => {
console.log('服务启动在3000端口');
});
前端实现示例
前端通过EventSource API连接后端的SSE接口,接收进度数据并更新界面:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XML处理进度</title>
</head>
<body>
<div>
<button onclick="startProcess()">开始处理XML文件</button>
</div>
<div id="progressContainer" style="margin-top: 20px; display: none;">
<div>当前状态:<span id="status"></span></div>
<div style="width: 300px; height: 20px; border: 1px solid #ccc; margin-top: 10px;">
<div id="progressBar" style="height: 100%; background: #4caf50; width: 0;"></div>
</div>
<div>进度:<span id="progressText">0</span>%</div>
</div>
<div id="errorMsg" style="color: red; margin-top: 10px;"></div>
<script>
function startProcess() {
const progressContainer = document.getElementById('progressContainer');
const statusEl = document.getElementById('status');
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
const errorMsg = document.getElementById('errorMsg');
// 显示进度容器
progressContainer.style.display = 'block';
errorMsg.innerText = '';
// 创建EventSource连接
const eventSource = new EventSource('http://127.0.0.1:3000/process-xml');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
// 处理错误情况
if (data.progress === -1) {
statusEl.innerText = data.status;
errorMsg.innerText = data.error || '';
eventSource.close();
return;
}
// 更新状态和进度
statusEl.innerText = data.status;
progressBar.style.width = data.progress + '%';
progressText.innerText = data.progress;
// 进度100%时关闭连接
if (data.progress === 100) {
eventSource.close();
}
};
eventSource.onerror = () => {
statusEl.innerText = '连接异常,请重试';
eventSource.close();
};
}
</script>
</body>
</html>
注意事项
在实际使用SSE通知XML处理进度时,需要注意以下几点:
- 如果XML文件过大,拆分进度时要避免推送频率过高,否则会增加服务端和客户端的负担,可以设置最小推送间隔,比如每提升5%再推送一次
- SSE默认不支持跨域,如果需要跨域访问,服务端需要设置
Access-Control-Allow-Origin响应头 - 如果处理过程中出现异常,要及时推送错误信息并关闭SSE连接,避免连接一直保持占用资源
- 部分旧版浏览器不支持
EventSourceAPI,如果需要兼容,可以使用polyfill库或者改用WebSocket实现类似功能
SSEXML文件处理进度通知EventSource修改时间:2026-07-17 14:48:38