Google Apps Script 表单文件上传与后端处理:两种策略详解

37次阅读

Google Apps Script 表单文件上传与后端处理:两种策略详解

本教程详细介绍了在 Google Apps Script 环境下,如何从 HTML 前端后端服务器函数提交包含文件和图像的表单数据。我们将探讨两种主要策略:一是利用 google.script.run 直接提交表单对象,将文件作为 Blob 处理;二是客户端通过 Drive API 预先上传文件至 Google Drive,然后将文件ID传递给后端。文章包含示例代码和注意事项,帮助开发者有效处理文件上传需求。

引言:Google Apps Script 文件上传的挑战

在 google apps script 开发中,当需要从 html 用户界面(前端)向 apps script 服务器端函数(后端)提交包含文件(如图片、文档)的表单数据时,开发者常会遇到挑战。由于 apps script 的沙盒环境限制,传统的浏览器 file api 或 formdata 对象在直接传递给 google.script.run 时可能无法按预期工作,尤其是在处理文件内容本身而非仅其元数据时。本教程将深入探讨两种有效的解决方案,帮助您克服这些挑战,实现文件与表单数据的无缝集成。

策略一:利用 google.script.run 直接提交表单对象

Google Apps Script 的 HTML Service 提供了一种简便的方式来处理表单提交,即直接将完整的 <form> 元素作为参数传递给服务器端函数。在这种模式下,Apps Script 会自动解析表单数据:常规的文本输入字段会被转换为字符串,而文件输入字段 (<input type=”file”>) 的内容则会被转换为 Apps Script 后端可识别的 Blob 对象。

原理阐述

当一个 <form> 元素被 google.script.run 调用时,它会被封装成一个 JavaScript 对象,其中表单字段的 name 属性作为键,其值作为对应的值。对于文件输入,其值不再是文件名字符串,而是 Apps Script 的 Blob 对象,可以直接用于 DriveApp.createFile() 等操作。

前端 HTML 结构

为了使服务器端能够正确识别表单字段,请确保所有输入元素都包含 name 属性。

<!DOCTYPE html> <html> <head>   <base target="_top"> </head> <body>   <form id="myForm" onsubmit="handleFormSubmit(this); return false;">     <label for="alertSelect">警报类型:</label>     <input name="alertSelect" id="alertSelect" type="text" value="事件" /><br><br>      <label for="alertSubject">警报主题:</label>     <input name="alertSubject" id="alertSubject" type="text" value="系统维护通知" /><br><br>      <label for="imageUpload">上传图片:</label>     <input name="myFile" id="imageUpload" type="file" /><br><br>      <input type="submit" value="提交表单" />   </form>    <div id="status"></div>    <script>     function handleFormSubmit(formObject) {       document.getElementById('status').innerText = '正在提交...';       google.script.run         .withSuccessHandler(updateStatus)         .withFailureHandler(showError)         .processForm(formObject);     }      function updateStatus(fileUrl) {       document.getElementById('status').innerText = '文件上传成功,链接:' + fileUrl;       document.getElementById('myForm').reset(); // 清空表单     }      function showError(error) {       document.getElementById('status').innerText = '提交失败: ' + error.message;       console.error(error);     }   </script> </body> </html>

后端 Google Apps Script (Code.gs) 处理

在服务器端,您可以通过 formObject 参数直接访问表单字段。文件输入字段的值将是一个 Blob 对象。

/**  * 接收前端提交的表单对象,处理文件和文本数据。  * @param {Object} formObject 包含表单字段和文件 Blob 的对象。  * @returns {string} 上传文件的 Google Drive URL。  */ function processForm(formObject) {   // 访问文本字段   var alertType = formObject.alertSelect;   var alertSubject = formObject.alertSubject;   Logger.log('警报类型: ' + alertType);   Logger.log('警报主题: ' + alertSubject);    // 访问文件 Blob   var fileBlob = formObject.myFile;    if (fileBlob && fileBlob.getName()) { // 检查文件是否存在     try {       // 使用 DriveApp.createFile() 将 Blob 保存到 Google Drive       var driveFile = DriveApp.createFile(fileBlob);       Logger.log('文件 "' + driveFile.getName() + '" 已上传到 Google Drive,ID: ' + driveFile.getId());       // 返回文件 URL 或 ID       return driveFile.getUrl();     } catch (e) {       Logger.log('文件上传失败: ' + e.message);       throw new Error('文件上传失败: ' + e.message);     }   } else {     Logger.log('未上传文件。');     return '未上传文件。';   } }

优点与局限

  • 优点: 实现简单,无需手动处理 FormData 或 OAuth 令牌,适合单个文件或少量文件的简单上传场景。
  • 局限: 对于多文件上传、需要指定上传文件夹、或者需要更细粒度控制上传过程(如进度条、分块上传)的场景,此方法可能不够灵活。同时,所有非文件字段都会被转换为字符串,如果需要保持原始数据类型(如数字、布尔值),需要在后端进行额外的类型转换。

策略二:客户端通过 Drive API 预先上传文件至 Google Drive

当需要处理多个文件、精确控制文件上传到 Google Drive 的目标文件夹,或者需要更灵活的上传流程时,可以在客户端(前端)直接调用 Google Drive API 进行文件上传。这种方法涉及到在前端获取 Apps Script 的 OAuth 令牌,并使用 fetch API 向 Drive API 发送请求。文件上传成功后,将返回的文件 ID 传递给 Apps Script 后端进行后续处理。

Google Apps Script 表单文件上传与后端处理:两种策略详解

简篇AI排版

AI排版工具,上传图文素材,秒出专业效果!

Google Apps Script 表单文件上传与后端处理:两种策略详解200

查看详情 Google Apps Script 表单文件上传与后端处理:两种策略详解

原理阐述

  1. 获取 OAuth 令牌: Apps Script 后端通过 ScriptApp.getOAuthToken() 获取当前用户的访问令牌,并将其传递给前端 HTML 模板。
  2. 前端上传文件: 前端 JavaScript 使用 fetch API,构造 multipart/form-data 请求,将文件数据连同元数据(如文件名、父文件夹ID)发送到 Google Drive API 的 /upload/drive/v3/files 端点。请求头中需包含 Authorization: Bearer <OAuth Token>。
  3. 传递文件 ID: 文件上传成功后,Drive API 返回的文件 ID 会被收集起来,然后作为表单数据的一部分,通过 google.script.run 传递给 Apps Script 后端。
  4. 后端处理: 后端接收到文件 ID 后,可以使用 DriveApp.getFileById() 访问这些文件,并进行进一步操作(如将其链接保存到 Google Sheet,或作为附件发送邮件)。

前端获取 OAuth 令牌 (Code.gs)

您需要在 doGet() 函数中将 OAuth 令牌传递给 HTML 模板。

/**  * 处理 GET 请求,渲染 HTML 模板并注入 OAuth 令牌。  * @param {Object} e 事件对象。  * @returns {HtmlOutput} 渲染后的 HTML 内容。  */ function doGet(e) {   var htmlTemplate = HtmlService.createTemplateFromFile('index.html');   // 注入 OAuth 令牌,前端将使用此令牌调用 Drive API   htmlTemplate.dataFromServerTemplate = { OAuthToken : ScriptApp.getOAuthToken() };   return htmlTemplate.evaluate(); }

前端 JavaScript (index.html)

前端代码将负责遍历选定的文件,为每个文件调用 Drive API 进行上传,并收集返回的文件 ID。

<!DOCTYPE html> <html> <head>   <base target="_top"> </head> <body>   <form id="myForm">     <label for="alertSelect">警报类型:</label>     <input name="alertSelect" id="alertSelect" type="text" value="事件" /><br><br>      <label for="alertSubject">警报主题:</label>     <input name="alertSubject" id="alertSubject" type="text" value="系统维护通知" /><br><br>      <label for="imageUpload">上传图片:</label>     <input name="imageUpload" id="imageUpload" type="file" multiple /><br><br> <!-- 允许多文件上传 -->      <button type="button" onclick="saveAlertWithFiles()">提交表单 (带文件)</button>   </form>    <div id="status"></div>    <script>     // 假设 data 变量已通过模板注入 OAuthToken     var data = <?!= JSON.stringify(dataFromServerTemplate) ?>;      async function saveAlertWithFiles() {       document.getElementById('status').innerText = '正在上传文件...';       let fileInput = document.getElementById("imageUpload");       let accessToken = data.OAuthToken;       // 替换为您的 Google Drive 目标文件夹 ID (可选)       let folderId = "YOUR_GOOGLE_DRIVE_FOLDER_ID";        let imageIds = [];        if (fileInput.files.length > 0) {         for (let i = 0; i < fileInput.files.length; i++) {           let file = fileInput.files[i];           let formData = new FormData();            // 构建文件元数据,包括文件名和目标文件夹           formData.append('metadata', new Blob([JSON.stringify({             name: file.name,             // 如果指定了文件夹ID,则上传到该文件夹             parents: folderId ? [folderId] : []            })], { type: 'application/json' }));           formData.append('file', file); // 文件的二进制数据            try {             let response = await fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart', {               method: 'POST',               headers: { 'Authorization': `Bearer ${accessToken}` },               body: formData             });             let result = await response.json();             if (result.id) {               imageIds.push(result.id);               console.log(`文件 "${file.name}" 上传成功,ID: ${result.id}`);             } else {               console.error(`文件 "${file.name}" 上传失败:`, result);               document.getElementById('status').innerText = `文件 "${file.name}" 上传失败。`;               return; // 遇到错误停止             }           } catch (error) {             console.error(`上传文件 "${file.name}" 时发生错误:`, error);             document.getElementById('status').innerText = `上传文件 "${file.name}" 时发生错误。`;             return; // 遇到错误停止           }         }       }        document.getElementById('status').innerText = '文件上传完成,正在提交表单数据...';        // 构建其他表单数据,并将 imageIds 包含进去       let record = {         'Alert Type': document.getElementById('alertSelect').value,         'Alert Subject': document.getElementById('alertSubject').value,         'Images': imageIds, // 传递文件ID数组         'Alert Active': true       };        let out = [record]; // 按照原始问题中的数据结构        // 将 record 传递给后端       google.script.run         .withSuccessHandler(clearForm)         .withFailureHandler(showError)         .saveAlerts(out);     }      function clearForm() {       document.getElementById('status').innerText = '表单提交成功!';       document.getElementById('myForm').reset();     }      function showError(error) {       document.getElementById('status').innerText = '表单提交失败: ' + error.message;       console.error(error);     }   </script> </body> </html>

后端 Google Apps Script (Code.gs) 处理

后端函数将接收一个包含文件 ID 数组的数据对象。您可以使用这些 ID 来检索文件,并进行后续操作。

/**  * 接收前端提交的表单数据和文件ID数组。  * @param {Array<Object>} data 包含表单字段和文件ID数组的对象。  */ function saveAlerts(data) {   Logger.log('接收到的数据: ' + JSON.stringify(data));    if (!data || data.length === 0) {     throw new Error("未接收到任何数据。");   }    let record = data[0]; // 假设只处理第一个记录   let alertType = record['Alert Type'];   let alertSubject = record['Alert Subject'];   let imageIds = record['Images']; // 获取文件ID数组    // 示例:将数据保存到 Google Sheet (假设 alerts 是一个 Spreadsheet 对象)   // var alerts = SpreadsheetApp.getActive

以上就是Google Apps Script 表单文件上传与javascript java html js 前端 json go 浏览器 app access 后端 ai JavaScript html 数据类型 封装 Token 字符串 类型转换 对象 input

javascript java html js 前端 json go 浏览器 app access 后端 ai JavaScript html 数据类型 封装 Token 字符串 类型转换 对象 input

text=ZqhQzanResources