如何仅用客户端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方法执行这段代码:
- 将所有JS代码(包括JSZip的代码)合并成一个字符串
- 在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
相关产品推荐
相关产品推荐

