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

无法上传大于500MB的.tar.gz文件,求JavaScript客户端解决方案

大文件上传解决方案(500MB+ .tar.gz)

你的代码崩溃的核心原因是一次性将整个大文件加载到内存,readFile会把文件全部读入内存,500MB以上的文件会直接耗尽客户端内存导致崩溃。另外,请求头里的Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Credentials是服务端响应头,客户端请求时不需要设置,直接删掉即可。

以下是针对不同场景的解决方案:

一、Electron环境(支持文件路径读取)

如果你的客户端是Electron应用,可以通过创建文件流实现流式上传,避免加载整个文件到内存:

const fs = require('fs');
const { Readable } = require('stream');
const axios = require('axios');

async uploadMapFile(url, filePath, mapType) {
  try {
    const contentType = mapType === "navi" ? "application/zip" : "application/tar+gzip";
    // 创建文件可读流
    const fileStream = fs.createReadStream(filePath);
    // 转换为axios支持的Web流格式
    const stream = Readable.toWeb(fileStream);
    
    const { data } = await axios.put(url, stream, {
      headers: {
        "Content-Type": contentType
      },
      // 禁用自动转换,确保流直接发送
      transformRequest: [(data) => data]
    });

    console.log("文件上传完成", data, mapType);
    await this.afterFileUpload(mapType);
    this.store.mapUploadFlag = false;
  } catch (error) {
    console.error("上传失败", error);
    this.store.mapUploadFailed = true;
  }
},

这种方式会逐块读取文件并发送,内存占用始终保持在较低水平。

二、纯浏览器环境(仅支持用户选择的File对象)

浏览器出于安全限制,无法直接通过文件路径读取文件,必须通过用户选择(<input type="file">)获取File对象。此时可以通过分片上传实现大文件传输:

async uploadMapFile(url, file, mapType) {
  try {
    const contentType = mapType === "navi" ? "application/zip" : "application/tar+gzip";
    const chunkSize = 10 * 1024 * 1024; // 10MB分片大小
    const totalChunks = Math.ceil(file.size / chunkSize);

    for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
      const start = chunkIndex * chunkSize;
      const end = Math.min(start + chunkSize, file.size);
      // 分割文件为当前分片
      const chunk = file.slice(start, end);

      // 上传分片,需服务端支持分片接收与合并
      const { data } = await axios.put(
        `${url}?chunkIndex=${chunkIndex}&totalChunks=${totalChunks}`,
        chunk,
        {
          headers: {
            "Content-Type": contentType,
            "Content-Range": `bytes ${start}-${end-1}/${file.size}` // 告知服务端分片范围
          }
        }
      );

      console.log(`分片 ${chunkIndex+1}/${totalChunks} 上传完成`, data);
    }

    // 所有分片上传完成后,通知服务端合并文件
    await axios.post(`${url}/merge`, { fileName: file.name, totalChunks });

    console.log("文件上传完成", mapType);
    await this.afterFileUpload(mapType);
    this.store.mapUploadFlag = false;
  } catch (error) {
    console.error("上传失败", error);
    this.store.mapUploadFailed = true;
  }
},

使用说明:

  1. 调用时传入用户选择的File对象(而非文件路径):
    // 示例:input选择文件后获取File对象
    document.querySelector('input[type="file"]').addEventListener('change', async (e) => {
      const file = e.target.files[0];
      await uploadMapFile('你的上传URL', file, 'tar.gz');
    });
    
  2. 服务端需要配合实现分片接收、存储与合并逻辑,否则无法完成最终文件组装。

关键注意事项

  • 流式/分片上传的核心是避免一次性加载整个文件到内存,始终处理小块数据。
  • 浏览器端无法绕过安全限制直接读取本地文件路径,必须通过用户交互获取File对象。
  • 上传大文件时,建议添加进度监听(axios可通过onUploadProgress回调实现),提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 15:16:24