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

如何仅用客户端JavaScript实现本地目录压缩并上传至API端点

纯客户端JavaScript实现目录选择、压缩与上传方案

可行性说明

完全可以实现,前提是你用的是Chrome/Edge等Chromium系浏览器(符合你指定user-data-dir的测试环境),同时需要引入一个轻量的JS压缩库(比如JSZip,纯客户端运行,无需后端支持)。

分步实现代码

1. 选择本地目录(无HTML表单)

用Chrome原生的showDirectoryPicker API直接唤起目录选择框,获取目录读取权限:

// 选择目标目录
async function selectDirectory() {
  try {
    // 唤起系统目录选择器,请求目录读取权限
    const dirHandle = await window.showDirectoryPicker();
    return dirHandle;
  } catch (err) {
    console.error('目录选择失败:', err);
    return null;
  }
}

2. 遍历目录并压缩为ZIP文件

首先要引入JSZip库(提前下载其minified版本代码,合并到你的脚本中),然后递归遍历目录下所有文件,添加到压缩包:

// 递归遍历目录,收集所有文件(含子目录)
async function getAllFiles(dirHandle, currentPath = '') {
  const fileList = [];
  // 遍历目录下的所有条目
  for await (const [entryName, entryHandle] of dirHandle.entries()) {
    const fullPath = currentPath + entryName;
    if (entryHandle.kind === 'file') {
      // 是文件,获取File对象
      const file = await entryHandle.getFile();
      fileList.push({ path: fullPath, file });
    } else if (entryHandle.kind === 'directory') {
      // 是子目录,递归遍历
      const subFiles = await getAllFiles(entryHandle, fullPath + '/');
      fileList.push(...subFiles);
    }
  }
  return fileList;
}

// 压缩目录为ZIP Blob对象
async function compressDirectory(dirHandle) {
  const zip = new JSZip();
  const allFiles = await getAllFiles(dirHandle);

  // 将每个文件添加到ZIP包中
  for (const { path, file } of allFiles) {
    const fileContent = await file.arrayBuffer();
    zip.file(path, fileContent);
  }

  // 生成ZIP格式的Blob(可直接用于上传)
  return zip.generateAsync({ type: 'blob' });
}

3. 上传ZIP包到Flask API端点

用原生fetch API构造请求,无需HTML表单:

// 上传ZIP文件到指定API
async function uploadZip(zipBlob, apiEndpoint) {
  try {
    const formData = new FormData();
    // 这里的字段名'file'要和你Flask后端接收的参数名一致(和原表单保持一致)
    formData.append('file', zipBlob, 'user-data-dir.zip');

    const response = await fetch(apiEndpoint, {
      method: 'POST',
      body: formData
    });

    if (response.ok) {
      console.log('上传成功');
      return await response.text();
    } else {
      console.error('上传失败,状态码:', response.status);
      return null;
    }
  } catch (err) {
    console.error('上传请求出错:', err);
    return null;
  }
}

整合完整流程

将上述函数串联,执行完整的选择-压缩-上传流程:

// 主流程函数
async function processUserDataDir(apiUrl) {
  // 1. 选择目录
  const dirHandle = await selectDirectory();
  if (!dirHandle) return;

  // 2. 压缩目录
  const zipBlob = await compressDirectory(dirHandle);
  if (!zipBlob) return;

  // 3. 上传压缩包
  const result = await uploadZip(zipBlob, apiUrl);
  console.log('处理结果:', result);
}

// 调用时替换为你的Flask API地址
// processUserDataDir('http://你的Flask服务器地址/upload');

在Selenium/Robot Framework中执行

你可以在测试结束后,通过Selenium的execute_script方法执行这段代码:

  1. 将所有JS代码(包括JSZip的代码)合并成一个字符串
  2. 在Robot Framework中执行:
# 注入JS代码(含JSZip)
Execute JavaScript    ${FULL_JS_CODE}
# 执行主流程,替换为你的API地址
Execute JavaScript    processUserDataDir('http://your-flask-server/upload');

兼容旧版Chrome(可选)

如果你的Chrome版本低于86,不支持showDirectoryPicker,可以用动态创建隐藏输入框的方式选择目录(注意这种方式无法保留完整目录层级):

// 旧版Chrome目录选择方式
function selectDirectoryLegacy() {
  return new Promise((resolve, reject) => {
    const input = document.createElement('input');
    input.type = 'file';
    input.webkitdirectory = true;
    input.style.display = 'none';
    document.body.appendChild(input);

    input.addEventListener('change', () => {
      if (input.files.length === 0) {
        reject(new Error('未选择目录'));
        return;
      }
      resolve(input.files);
      document.body.removeChild(input);
    });

    input.click();
  });
}

使用此方法时,需要修改compressDirectory函数以适配FileList对象,且压缩后的ZIP会丢失原目录的层级结构。


内容的提问来源于stack exchange,提问作者Victor Andres Aguirre Fernande

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 04:25:39