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

如何将本地剪贴板图片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);
  }
}

解决方案

核心问题说明

  1. 用FormData上传文件时,GAS的doPost函数不会将文件数据放在e.postData中,而是存于e.files对象里。
  2. 跨域请求需要GAS部署时允许匿名访问,并在响应中添加CORS头。
  3. 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部署步骤

  1. 保存GAS代码后,点击右上角「部署」→「新部署」。
  2. 类型选择「Web应用」。
  3. 执行权限选择「我」,谁可以访问选择「任何人,甚至匿名」。
  4. 点击「部署」,复制生成的Web应用URL,替换客户端代码中的地址。

内容的提问来源于stack exchange,提问作者1min

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 05:44:55