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

Node.js实现AWS S3文件备份API无法读取用户本地文件问题

问题根因

Web服务端没有直接访问用户本地文件系统的权限,现有代码的核心逻辑错误在于:把前端传入的本地路径字符串当作服务端本地路径,调用fs模块在服务端磁盘上检索文件。浏览器出于安全沙箱限制,既不允许网页随意读取用户本地任意路径的文件,也不可能允许远程服务端直接操作用户磁盘,这套逻辑从Web安全模型层面就走不通。

实现方案
  • 废弃「接收前端传文件路径、服务端按路径读取本地文件」的逻辑,改用标准的HTTP文件上传流程:用户主动在前端选择要上传的文件/文件夹,浏览器把文件内容打包到请求体中传给后端,后端直接解析请求体里的文件内容上传S3。
  • 文件夹上传场景不需要用户手动输入路径,前端使用带文件夹选择属性的文件控件,让用户主动授权选中要上传的文件夹,浏览器会自动遍历文件夹内容、保留相对目录结构。
    前端参考实现:
    <!-- 文件夹选择控件,支持直接选中整个目录 -->
    <input type="file" id="folderPicker" webkitdirectory directory multiple />
    
    const folderPicker = document.getElementById('folderPicker');
    folderPicker.addEventListener('change', async (e) => {
      const fileList = e.target.files;
      const formData = new FormData();
      // 填充版本相关的普通字段
      formData.append('versionName', '输入的版本名称');
      formData.append('versionDescription', '输入的版本描述');
      // 遍历所有选中的文件,保留原相对路径
      for (const file of fileList) {
        // webkitRelativePath 会返回文件在所选文件夹下的相对路径,例:项目文件夹/src/index.js
        formData.append('uploadFiles', file, file.webkitRelativePath);
      }
      // 携带认证信息发送请求到后端接口
      await fetch(`/create/${对应项目ID}`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${用户登录凭证}`
        },
        body: formData
      })
    })
    
  • 后端改造原有逻辑:不再读取请求字段里的路径参数调用fs遍历服务端磁盘,直接解析multipart请求中携带的文件列表,基于文件自带的相对路径拼接S3存储键,上传完成后清理multiparty生成的临时文件即可。
    后端文件上传处理参考:
    // 替换原有的sync_folders方法,直接处理前端上传的文件列表
    const sync_uploaded_to_s3 = async (fileList, s3BaseKey) => {
      const uploadResult = [];
      for (const file of fileList) {
        // 兼容单文件、多文件场景,统一转成数组处理
        const processFiles = Array.isArray(file) ? file : [file];
        for (const singleFile of processFiles) {
          // 取前端传过来的相对路径
          const relativePath = singleFile.originalFilename;
          const s3Key = `${s3BaseKey}/${relativePath}`;
          // 读取multiparty存在临时目录的文件流
          const fileStream = fs.createReadStream(singleFile.path);
          const uploadRes = await s3.upload({
            Bucket: 存储桶名,
            Key: s3Key,
            Body: fileStream,
            ContentType: singleFile.headers['content-type'],
            ContentLength: singleFile.size
          }).promise();
          uploadResult.push(uploadRes);
          // 上传完成删除临时文件,避免磁盘占满
          fs.unlinkSync(singleFile.path);
        }
      }
      return uploadResult;
    }
    
    // 路由部分改造:把原来读取files_path调用sync_folders的逻辑替换为以下代码
    // const uploadedFiles = files.uploadFiles;
    // const s3BaseKey = `${user.firstName}_${user_id}/${project.projectName}/${fields.versionName[0]}`;
    // const version_folder_list = await sync_uploaded_to_s3(uploadedFiles, s3BaseKey);
    

如果需要实现「后台静默同步用户指定本地文件夹、不需要用户每次手动选择」的能力,纯Web页面无法实现——浏览器没有静默访问本地文件的权限。这类场景需要开发本地安装的客户端程序(比如Electron桌面应用、本地运行的同步守护进程),由本地客户端扫描指定路径的文件,主动调用服务端接口完成上传。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 23:51:35