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

Electron下载文件时如何校验完整性避免损坏且节省用户流量?

现有代码的核心问题

  • 采用fetch + blob全量加载模式,文件整体存入内存后再写入磁盘,200MB以上文件会占用过高内存,网络中断时所有已下载内容直接作废,必须重下整个文件
  • 路径拼接硬编码Windows反斜杠,无法兼容macOS、Linux系统
  • 同步读写API会阻塞渲染进程,界面可能出现卡顿

大文件下载优化方案

1. 流式下载 + 断点续传(核心解决流量浪费问题)

放弃fetch全量下载逻辑,改用Node.js https 模块实现流式下载,边下载边写入磁盘,无需占用全量内存。同时支持断点续传,网络中断后只需下载未完成的部分:

  • 先发起HEAD请求获取文件总大小,校验服务端是否支持Range断点续传(响应头包含Accept-Ranges: bytes)
  • 每次下载前先读取本地已下载的临时文件大小,请求时携带Range: bytes=已下载大小-头,从断点位置继续下载
  • 临时文件下载完成后再重命名为正式文件名,避免中途退出产生损坏的正式文件
  • 如果你不想自己实现完整的下载逻辑,也可以直接调用Electron内置的session.download API,原生支持断点续传、进度监听、取消暂停等能力,稳定性更高

2. 完整性校验方案

  • 单文件MD5校验完全能覆盖普通下载损坏的场景,可靠性足够。建议让服务端将对应文件的MD5值放在响应头的自定义字段(例如X-File-MD5)中,下载完成后本地计算文件MD5与响应头值比对即可,无需额外请求接口
  • 若需要进一步节省重传流量,可以要求服务端按固定块大小(例如10MB/块)计算每块的哈希值并返回哈希列表,你每下载完一个块就校验对应哈希,仅重传校验失败的块即可,不需要重下整个文件

优化后的核心代码示例

const https = require('https');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

async function downloadFile(downloadURL, downloadDir, filename) {
  // 跨平台拼接路径
  const fullPath = path.join(downloadDir, filename);
  const tempPath = fullPath + '.tmp';
  
  // 创建目录
  if (!fs.existsSync(downloadDir)) {
    fs.mkdirSync(downloadDir, { recursive: true });
  }

  // 读取已下载的临时文件大小
  let downloadedSize = 0;
  if (fs.existsSync(tempPath)) {
    downloadedSize = fs.statSync(tempPath).size;
  }

  return new Promise((resolve, reject) => {
    const options = new URL(downloadURL);
    // 断点续传头
    options.headers = downloadedSize > 0 ? { Range: `bytes=${downloadedSize}-` } : {};

    https.get(options, (res) => {
      // 206是断点续传成功响应码,200是全量下载成功响应码
      if (res.statusCode !== 200 && res.statusCode !== 206) {
        return reject(new Error(`下载失败,响应码:${res.statusCode}`));
      }

      // 读取服务端返回的文件MD5
      const serverMD5 = res.headers['x-file-md5'];
      // 以追加模式写入临时文件
      const writeStream = fs.createWriteStream(tempPath, { flags: downloadedSize > 0 ? 'a' : 'w' });
      const hash = crypto.createHash('md5');

      res.pipe(writeStream);
      // 边下载边计算MD5
      res.on('data', (chunk) => hash.update(chunk));

      writeStream.on('finish', () => {
        writeStream.close();
        // 校验文件完整性
        const localMD5 = hash.digest('hex');
        if (serverMD5 && localMD5 !== serverMD5) {
          fs.unlinkSync(tempPath);
          return reject(new Error('文件校验失败,已删除损坏文件'));
        }
        // 校验通过后重命名为正式文件
        fs.renameSync(tempPath, fullPath);
        resolve(fullPath);
      });

      writeStream.on('error', (err) => {
        writeStream.close();
        reject(err);
      });
    }).on('error', reject);
  });
}

// 调用示例
downloadFile("https://sample.com/test.zip", "SOME_DIRECTORY_HERE", "test.zip")
  .then(() => console.log("下载完成"))
  .catch(console.error);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:54:03