如何将Express服务端的console.log数据发送到前端实现下载进度条
实现下载进度同步的解决方案
核心思路
你当前的问题是普通HTTP请求为一次性响应模式,服务端处理请求时没有主动向客户端推送实时数据,因此前端无法拿到进度。这里直接用Server-Sent Events(SSE) 即可实现,它是HTTP原生支持的单向推送协议,无需引入WebSocket等复杂方案,完全适配你的需求场景。
第一步:修改服务端代码
调整后的Server.js代码如下,核心改动是新增SSE响应头、实时推送进度数据、处理下载完成/错误逻辑:
app.get('/', async (req, res) => { // 1. 设置SSE响应头,开启长连接推送 res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Access-Control-Allow-Origin': '*' }); fetch(`https://api.github.com/repos/${options.gitUser}/${options.gitRepo}/releases/latest`) .then(response => response.json()) .then(data => { let zip; // 注意:原代码的i未声明,这里补let for (let i = 0; i < data['assets'].length; i++) { if (data['assets'][i]['name'] === `${options.softName}`) zip = data['assets'][i]; } let received_bytes = 0; let total_bytes = 0; // 注意:原代码变量名和路由req重名,这里改名为downloadReq const downloadReq = request({ method: 'GET', uri: zip['browser_download_url'] }); // 注意:路径反斜杠需要转义,改为双反斜杠 const out = fs.createWriteStream(`C:\\Users\\${options.userName}\\AppData\\Roaming\\Camnor\\Camsoft\\${options.softName}`); downloadReq.pipe(out); downloadReq.on('response', data => { total_bytes = parseInt(data.headers['content-length']); }); downloadReq.on('data', chunk => { received_bytes += chunk.length; // 2. 实时推送进度数据到前端 res.write(`data: ${JSON.stringify({received: received_bytes, total: total_bytes})}\n\n`); }); // 3. 下载完成后关闭连接 downloadReq.on('end', () => { res.write(`data: ${JSON.stringify({status: 'done'})}\n\n`); res.end(); }); // 4. 处理下载错误,避免连接挂死 downloadReq.on('error', (err) => { res.write(`data: ${JSON.stringify({status: 'error', msg: err.message})}\n\n`); res.end(); }); }); })
第二步:修改前端调用逻辑
替换原来的fetch逻辑,用原生EventSource监听服务端推送的进度数据即可:
Neutralino.os.execCommand('server-win.exe'); // 监听SSE推送的进度 const progressSource = new EventSource('http://localhost:3000'); progressSource.onmessage = (event) => { const data = JSON.parse(event.data); if (data.status === 'done') { // 下载完成,关闭连接 progressSource.close(); console.log('下载完成'); return; } if (data.status === 'error') { console.error('下载出错:', data.msg); progressSource.close(); return; } // 这里计算进度百分比,更新你的进度条UI const percent = ((data.received / data.total) * 100).toFixed(2); console.log(`当前进度:${percent}%`); }; progressSource.onerror = (err) => { console.error('进度推送连接出错:', err); progressSource.close(); };
注意事项
- 如果你的服务端需要同时处理多个下载任务,建议给每个下载请求加唯一标识,避免进度数据混淆
- 生产环境可以移除
Access-Control-Allow-Origin: *,改成你的前端实际访问地址,提升安全性 - 要处理页面关闭等场景的连接断开逻辑,避免服务端产生无效长连接
内容的提问来源于stack exchange,提问作者Meilleur102
相关产品推荐
相关产品推荐

