如何将本地剪贴板图片Blob发送至Google Apps Script并解决e.postData未定义问题
问题描述
我希望将客户端JavaScript获取的剪贴板图片Blob数据发送至跨域的Google Apps Script(GAS)服务器,以存储到Google Drive中。但尝试现有代码后无法正常运行:Google Apps Script端的e.postData参数始终返回undefined。不清楚这是JavaScript fetch的问题还是服务器端的问题,也不确定是否需要先将JavaScript Blob数据转换为纯文本字符串后再发送,求可运行的示例代码。
原客户端HTML/JS代码(本地Chrome扩展环境)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script> window.addEventListener("DOMContentLoaded", function () { document.querySelector("#test").addEventListener("click", async () => { try { const permission = await navigator.permissions.query({ name: "clipboard-read", }); // permission allowed if (permission.state === "granted") { const dataTransfer = await navigator.clipboard.read(); // get item from clipboard for (const item of dataTransfer) { const isImage = item.types.some((type) => type === "image/png"); if (!isImage) { continue; } // get Blob from clipboardItem const blob = await item.getType("image/png"); var formData = new FormData(); formData.append("blobData", blob); fetch("my_google_apps_script_url", { method: "POST", body: formData, }) .then((response) => response.json()) .then((data) => { console.log("Response from Google Apps Script:", data); }) .catch((error) => { console.error("Error calling Google Apps Script:", error); }); break; } } else { console.log("not allowed permission."); } } catch (error) { console.error("clipboard read error:", error); } }); }); </script> </head> <body> <button id="test">test button</button> </body> </html>
原Google Apps Script代码
function doPost(e) { try { // e.postData is null // I will get blob from e.postData and store in my google drive. return ContentService.createTextOutput(JSON.stringify({ success: true })) .setMimeType(ContentService.MimeType.JSON); } catch (error) { console.error('Error processing Blob data:', error); return ContentService.createTextOutput(JSON.stringify({ success: false, error: error.message })) .setMimeType(ContentService.MimeType.JSON); } }
解决方案
核心问题说明
- 用
FormData上传文件时,GAS的doPost函数不会将文件数据放在e.postData中,而是存于e.files对象里。 - 跨域请求需要GAS部署时允许匿名访问,并在响应中添加CORS头。
- Chrome扩展环境下需确保
clipboard-read权限已在manifest.json中声明。
修正后的客户端代码
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>剪贴板图片上传</title> <script> window.addEventListener("DOMContentLoaded", () => { document.querySelector("#test").addEventListener("click", async () => { try { // 检查剪贴板权限 const permission = await navigator.permissions.query({ name: "clipboard-read" }); if (permission.state !== "granted") { console.log("未获取剪贴板读取权限"); return; } // 读取剪贴板数据 const dataTransfer = await navigator.clipboard.read(); for (const item of dataTransfer) { // 筛选PNG图片 if (!item.types.includes("image/png")) continue; const blob = await item.getType("image/png"); const formData = new FormData(); // 添加文件名,方便GAS识别处理 formData.append("uploadedImage", blob, `clipboard-img-${Date.now()}.png`); // 发送请求到GAS const response = await fetch("替换为你的GAS部署URL", { method: "POST", body: formData, mode: "cors" // 允许跨域 }); if (!response.ok) throw new Error(`HTTP错误:${response.status}`); const result = await response.json(); console.log("上传结果:", result); break; } } catch (err) { console.error("操作失败:", err); } }); }); </script> </head> <body> <button id="test">上传剪贴板图片</button> </body> </html>
Chrome扩展补充配置
在manifest.json中添加权限声明:
{ "manifest_version": 3, "name": "剪贴板图片上传", "version": "1.0", "permissions": ["clipboardRead"], "action": { "default_popup": "popup.html" } }
修正后的Google Apps Script代码
function doPost(e) { try { // 检查是否有上传的文件 if (!e.files || e.files.length === 0) { return createResponse({ success: false, error: "未接收到文件数据" }); } // 获取上传的图片文件 const file = e.files[0]; // 选择要存储的Drive文件夹(这里用根目录,可替换为文件夹ID) const folder = DriveApp.getRootFolder(); // 将文件保存到Drive const savedFile = folder.createFile(file); return createResponse({ success: true, fileId: savedFile.getId(), fileName: savedFile.getName(), fileUrl: savedFile.getUrl() }); } catch (error) { console.error("处理文件失败:", error); return createResponse({ success: false, error: error.message }); } } // 封装响应函数,添加CORS头 function createResponse(data) { return ContentService.createTextOutput(JSON.stringify(data)) .setMimeType(ContentService.MimeType.JSON) .setHeaders({ "Access-Control-Allow-Origin": "*", // 允许所有域跨域访问,生产环境可指定具体域名 "Access-Control-Allow-Methods": "POST", "Access-Control-Allow-Headers": "Content-Type" }); }
GAS部署步骤
- 保存GAS代码后,点击右上角「部署」→「新部署」。
- 类型选择「Web应用」。
- 执行权限选择「我」,谁可以访问选择「任何人,甚至匿名」。
- 点击「部署」,复制生成的Web应用URL,替换客户端代码中的地址。
内容的提问来源于stack exchange,提问作者1min
相关产品推荐
相关产品推荐

