如何向Google Apps Script Web应用传递不可序列化的JavaScript对象
解决方案
问题根因
所有通过UrlFetchApp传递到Apps Script Web App的参数都会被自动序列化为字符串,绑定脚本执行上下文的原生对象(Lock、File、Blob等)无法跨脚本实例传递,你遇到的报错均是因为传递后的参数已经丢失了原对象的所有方法和二进制内容,仅保留了纯文本描述。
具体错误说明
ScriptLock传递失效:Lock实例仅在当前脚本执行上下文生效,序列化后仅为普通字符串,自然不存在releaseLock方法。且跨脚本的Lock本身不具备锁效力,不需要传递。- 附件参数无效:
File/Blob对象序列化后仅保留类名和ID信息,无实际二进制内容,无法被GmailApp识别为合法附件。 - 转Blob后无附件:直接将
Blob放入payload会被自动转为toString()的文本结果,二进制内容完全丢失,因此邮件能发送但无附件。
修复方案(推荐:传文件ID,实现最简单)
核心逻辑调整
- 锁直接在调用端申请,等Web App请求返回后再释放,不需要传递给Web App
- 仅传递文件ID给Web App,由具备权限的Web App直接从Drive读取文件生成附件
修改后的代码
客户端 gs
function testEmail() { var attachmentFileId = "file id"; // 仅传递文件ID var emailBody = 'email body content'; sendEmailFromClient('sendTo@example.com', "test", emailBody, attachmentFileId, 'replyTo@example.com'); } function sendEmailFromClient(sendTo, title, body, attachmentFileId, replyTo) { var scriptLock = LockService.getScriptLock(); if(!scriptLock.tryLock(8000)){ return; } try { var formData = { 'sendTo': sendTo, 'title': title, 'body' : body, 'attachmentFileId': attachmentFileId, 'replyTo' : replyTo }; var options = { 'method': 'post', 'payload': formData }; Logger.log(UrlFetchApp.fetch('web app url', options).getContentText()); } finally { // 锁在当前上下文申请,就在当前上下文释放 scriptLock.releaseLock(); } }
Web App gs
function doPost(event) { var p = event.parameter; try { // 由具备权限的Web App读取文件生成附件 var attachment = DriveApp.getFileById(p.attachmentFileId).getBlob(); var result = Library['sendEmail'](p.sendTo, p.title, p.body, [attachment], p.replyTo); return ContentService.createTextOutput(result); } catch (error) { Library.troubleshooting(error); return ContentService.createTextOutput(error.toString()); } }
Library gs 修正版
function sendEmail(sendTo, title, body, attachments, replyTo) { // 替换为你实际的全局配置值 const gv_accountingEmail = "默认回复邮箱"; const gv_systemBrandName = "系统发件名称"; replyTo = replyTo || gv_accountingEmail; attachments = attachments || []; try { GmailApp.sendEmail( sendTo, // 修正原代码中无意义的sendTo.valid调用 title, "html content only", { attachments: attachments, replyTo: replyTo, name: gv_systemBrandName, htmlBody: body } ); return true; } catch (error) { return error.toString(); } }
备选方案:Web App无权限访问用户Drive时用Base64传附件
如果Web App的执行身份没有权限读取用户的Drive文件,可以把附件转成Base64编码传递:
客户端新增Blob转Base64逻辑
// 客户端获取blob后转base64,同时传递mimeType和文件名 var blob = DriveApp.getFileById("file id").getBlob(); var formData = { // 其他参数不变 'blobBase64': Utilities.base64Encode(blob.getBytes()), 'blobName': blob.getName(), 'blobType': blob.getContentType() }
Web App端还原Blob
var attachment = Utilities.newBlob( Utilities.base64Decode(p.blobBase64), p.blobType, p.blobName );
内容的提问来源于stack exchange,提问作者Alex Libengood
相关产品推荐
相关产品推荐

