fix(core): 修复nwjs下server端文件下载异常

This commit is contained in:
王立帮
2025-09-30 08:39:23 +08:00
parent f9d9c4c7ae
commit 5651def093
2 changed files with 71 additions and 32 deletions

View File

@@ -254,6 +254,9 @@ Setting.configMenuGetValue = (obj) => {
Setting.refreshUpdateMenuStatus = (localVersion, cloudVersion, needsUpdate, url) => { Setting.refreshUpdateMenuStatus = (localVersion, cloudVersion, needsUpdate, url) => {
const $serverDiv = $('#setting-menu-update-server'); const $serverDiv = $('#setting-menu-update-server');
const $btnDiv = $('#setting-menu-update > div:nth-child(2)'); const $btnDiv = $('#setting-menu-update > div:nth-child(2)');
const $button = $btnDiv.children('button');
$button.removeClass('layui-btn-disabled');
$button.addClass('self-adaption-btn');
const $mixlyProgress = $serverDiv.find('.mixly-progress'); const $mixlyProgress = $serverDiv.find('.mixly-progress');
$serverDiv.find('span').css('display', 'none'); $serverDiv.find('span').css('display', 'none');
$mixlyProgress.hide(); $mixlyProgress.hide();
@@ -269,7 +272,9 @@ Setting.refreshUpdateMenuStatus = (localVersion, cloudVersion, needsUpdate, url)
} }
if (needsUpdate) { if (needsUpdate) {
$btnDiv.css('display', 'flex'); $btnDiv.css('display', 'flex');
$btnDiv.children('button').off().one('click', (event) => { $button.off().one('click', (event) => {
$button.addClass('layui-btn-disabled');
$button.removeClass('self-adaption-btn');
const eventSource = new EventSource(`/api/download?url=${encodeURIComponent(url)}&cloudVersion=${cloudVersion}`); const eventSource = new EventSource(`/api/download?url=${encodeURIComponent(url)}&cloudVersion=${cloudVersion}`);
$mixlyProgress.show(); $mixlyProgress.show();
eventSource.onmessage = function(event) { eventSource.onmessage = function(event) {

View File

@@ -172,72 +172,106 @@ router.get('/download', async (req, res) => {
try { try {
const { url, cloudVersion } = req.query; const { url, cloudVersion } = req.query;
if(fs.existsSync(TEMP_FOLDER_PATH)) { // 清理临时文件夹
if (fs.existsSync(TEMP_FOLDER_PATH)) {
deleteFolderRecursive(TEMP_FOLDER_PATH); deleteFolderRecursive(TEMP_FOLDER_PATH);
} }
fs.mkdirSync(TEMP_FOLDER_PATH); fs.mkdirSync(TEMP_FOLDER_PATH, { recursive: true });
const filePath = path.resolve(TEMP_FOLDER_PATH, 'mixly.zip'); const filePath = path.resolve(TEMP_FOLDER_PATH, 'mixly.zip');
const fileStream = fs.createWriteStream(filePath); const fileStream = fs.createWriteStream(filePath);
// 设置响应头 // 设置 SSE 响应头
res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Transfer-Encoding', 'chunked'); res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.flushHeaders();
// 发起下载请求 // 发起下载请求 - 添加 NW.js 特定配置
const response = await axios({ const response = await axios({
method: 'GET', method: 'GET',
url: url, url: url,
responseType: 'stream' responseType: 'stream',
timeout: 60000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
},
adapter: require('axios/lib/adapters/http')
}); });
const totalSize = parseInt(response.headers['content-length'], 10); const totalSize = parseInt(response.headers['content-length'], 10) || 0;
let downloadedSize = 0; let downloadedSize = 0;
let lastProgress = 0; let lastProgress = 0;
// 发送进度信息 // 发送进度信息
const sendProgress = (progress) => { const sendProgress = (progress) => {
if(progress !== lastProgress) { if (progress !== lastProgress) {
res.write('data:' + JSON.stringify({ type: 'progress', progress }) + '\n\n'); const data = JSON.stringify({ type: 'progress', progress });
res.write(`data: ${data}\n\n`);
lastProgress = progress; lastProgress = progress;
} }
}; };
// 发送解压信息 // 管道流处理
const sendUnzip = () => {
res.write('data:' + JSON.stringify({ type: 'unzip' }) + '\n\n');
};
// 发送完成信息
const sendComplete = (version) => {
res.write('data:' + JSON.stringify({ type: 'complete', version }) + '\n\n');
res.end();
};
response.data.pipe(fileStream); response.data.pipe(fileStream);
// 处理数据流
// 进度监控
response.data.on('data', (chunk) => { response.data.on('data', (chunk) => {
downloadedSize += chunk.length; downloadedSize += chunk.length;
const progress = Math.round((downloadedSize / totalSize) * 100); if (totalSize > 0) {
sendProgress(progress); const progress = Math.round((downloadedSize / totalSize) * 100);
sendProgress(progress);
}
}); });
// 文件流完成
fileStream.on('finish', async () => { fileStream.on('finish', async () => {
// 获取版本信息并保存 console.log('文件下载完成,开始解压');
saveVersionInfo(cloudVersion);
sendUnzip(); // 发送解压信息
res.write(`data: ${JSON.stringify({ type: 'unzip' })}\n\n`);
try { try {
const asyncZip = new AsyncAdmZip(filePath); const asyncZip = new AsyncAdmZip(filePath);
await asyncZip.extractAllTo(path.resolve(__dirname, '../')); await asyncZip.extractAllTo(path.resolve(__dirname, '../'));
sendComplete(cloudVersion);
if(fs.existsSync(TEMP_FOLDER_PATH)) { // 保存版本信息
saveVersionInfo(cloudVersion);
// 发送完成信息
res.write(`data: ${JSON.stringify({ type: 'complete', version: cloudVersion })}\n\n`);
// 清理临时文件
if (fs.existsSync(TEMP_FOLDER_PATH)) {
deleteFolderRecursive(TEMP_FOLDER_PATH); deleteFolderRecursive(TEMP_FOLDER_PATH);
} }
res.end();
} catch (error) { } catch (error) {
console.log(error); console.error('解压失败:', error);
res.status(500).json({ error: '解压失败' }); res.write(`data: ${JSON.stringify({ type: 'error', message: '解压失败' })}\n\n`);
res.end();
} }
}); });
// 错误处理
response.data.on('error', (error) => {
console.error('下载流错误:', error);
res.write(`data: ${JSON.stringify({ type: 'error', message: '下载流错误' })}\n\n`);
res.end();
});
fileStream.on('error', (error) => {
console.error('文件流错误:', error);
res.write(`data: ${JSON.stringify({ type: 'error', message: '文件保存错误' })}\n\n`);
res.end();
});
} catch (error) { } catch (error) {
console.log(error.message); console.error('下载过程错误:', error);
res.status(500).json({ error: '下载失败' }); res.write(`data: ${JSON.stringify({ type: 'error', message: '下载失败: ' + error.message })}\n\n`);
res.end();
} }
}); });