You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Electron中用Ajax与FS下载保存.tar.gz文件损坏问题求助

Electron应用自动更新:下载.tar.gz文件损坏问题排查与优化

核心问题分析

  1. 二进制文件下载方式错误
    你用$.get请求下载.tar.gz二进制文件,而jQuery的$.get默认以文本格式处理响应,会对二进制数据进行字符编码转换,破坏原始二进制结构,最终导致文件损坏无法解压。浏览器直接下载时会自动识别并处理二进制数据,所以不会出现问题。

  2. 版本号比较逻辑错误
    r["tag_name"].slice(-6) <= current_version.slice(-6)这种字符串截取对比的方式完全不可靠。比如版本v1.0.10和v1.0.2,截取后得到1.0.10和1.0.2,字符串按字符逐个对比时,会认为1.0.10小于1.0.2,直接导致新版本判断失效。

修复方案

1. 正确下载二进制文件

方案一:用Node.js的https模块(推荐在主进程执行)

Electron主进程可直接使用Node.js API,处理文件下载和IO更稳定:

// 主进程代码示例
const https = require('https');
const fs = require('fs');
const { ipcMain } = require('electron');

// 监听渲染进程的下载请求
ipcMain.on('download-update', (event, url) => {
  const fileStream = fs.createWriteStream('release.tar.gz');
  https.get(url, (response) => {
    response.pipe(fileStream);
    fileStream.on('finish', () => {
      fileStream.close();
      event.reply('download-complete', 'Update downloaded');
    });
  }).on('error', (err) => {
    fs.unlink('release.tar.gz', () => {}); // 删除损坏的文件
    event.reply('download-error', err.message);
  });
});

渲染进程通过IPC通知主进程下载:

// 渲染进程代码
const { ipcRenderer } = require('electron');

$(document).on("click", "#download-new-version", () => {
  for (let asset of release_to_download["assets"]) {
    if (asset["content_type"] == "application/x-gzip") {
      ipcRenderer.send('download-update', asset["browser_download_url"]);
    }
  }
});

方案二:在渲染进程用XMLHttpRequest处理二进制

若需在渲染进程处理,需设置响应类型为blob:

$(document).on("click", "#download-new-version", () => {
  for (let asset of release_to_download["assets"]) {
    if (asset["content_type"] == "application/x-gzip") {
      const xhr = new XMLHttpRequest();
      xhr.open('GET', asset["browser_download_url"], true);
      xhr.responseType = 'blob';

      xhr.onload = function() {
        if (this.status === 200) {
          // 将Blob转Buffer后写入文件(建议通过IPC通知主进程操作)
          const fs = require('fs').promises;
          this.response.arrayBuffer().then(buffer => {
            fs.writeFile('release.tar.gz', Buffer.from(buffer));
            console.log("Update downloaded");
          });
        }
      };

      xhr.onerror = function(err) {
        console.error('Download failed:', err);
      };

      xhr.send();
    }
  }
});

2. 正确比较版本号

使用语义化版本比较库semver(项目中直接安装即可):

npm install semver

修改版本检查逻辑:

const semver = require('semver');

$(document).on("click", "#check-updates", () => {
  $.get('https://api.github.com/repos/PATH_TO_REPO/releases/latest')
    .then((r) => {
      // 去除版本号前缀(如v),提取纯版本字符串
      const latestVersion = r["tag_name"].replace(/^v/, '');
      const currentVersion = current_version.replace(/^v/, '');
      
      if (semver.lte(latestVersion, currentVersion)) { 
        $("#check-updates").html("No updates found.");
      } else {
        release_to_download = r;
      }
    })
    .catch(err => console.error('Check update failed:', err))
})

若不想依赖第三方库,可自行实现版本拆分对比:

function compareVersions(v1, v2) {
  const arr1 = v1.replace(/^v/, '').split('.').map(Number);
  const arr2 = v2.replace(/^v/, '').split('.').map(Number);
  
  for (let i = 0; i < Math.max(arr1.length, arr2.length); i++) {
    const num1 = arr1[i] || 0;
    const num2 = arr2[i] || 0;
    if (num1 > num2) return 1;
    if (num1 < num2) return -1;
  }
  return 0;
}

// 使用示例
if (compareVersions(latestVersion, currentVersion) <= 0) {
  // 无更新逻辑
}

代码优化建议

  • 避免全局变量:release_to_download作为全局变量容易引发意外覆盖,建议用闭包、模块变量或状态管理保存。
  • 完善错误处理:添加GitHub API请求失败、下载中断的catch逻辑,避免静默失败。
  • 文件操作移至主进程:Electron渲染进程操作文件系统存在安全风险,主进程的Node.js API更稳定,建议将下载、写入逻辑放在主进程,通过IPC与渲染进程通信。
  • 添加文件校验:下载完成后对比GitHub返回的asset的sha256哈希值,确保文件未损坏:
    // 主进程校验示例
    const crypto = require('crypto');
    const fs = require('fs');
    
    const hash = crypto.createHash('sha256');
    const stream = fs.createReadStream('release.tar.gz');
    
    stream.on('data', (data) => hash.update(data));
    stream.on('end', () => {
      const fileHash = hash.digest('hex');
      // 对比GitHub返回的asset.sha256
      if (fileHash === asset.sha256) {
        console.log('文件校验通过');
      } else {
        console.error('文件损坏,校验失败');
        fs.unlink('release.tar.gz', () => {});
      }
    });
    
  • 增强UI反馈:添加下载进度条、错误提示,提升用户体验。

内容的提问来源于stack exchange,提问作者Radvvan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 05:24:56