如何解决 Google Apps Script 开发中的常见错误

Ole*_*ter 6 debugging google-api google-apps-script google-apps-script-addon

问答目前是讨论的主题,请参与。目前的计划是在可能的情况下拆分为问答环节。A&A 的答案是社区维基,当状态得到解决时,问题应该成为一个问题。


前言

本问答力求成为Google Apps Script语言开发过程中遇到的常见错误的集合和参考对象,以期提高标签的长期可维护性。

在其他语言和通用标签中也有几个类似的成功经历(参见c++androidphpphp 再次),这一个也紧随其后。


它为什么存在?

新老开发人员提出的关于开发和生产过程中遇到的错误的含义和解决方案的问题数量很多,这些问题可以有效地简化为一个单一的答案。在撰写本文时,即使仅通过语言标签运行查询也会产生:

  • “找不到方法” 8页
  • “无法读取属性” 9 页
  • “在这种情况下无法调用 ...” 5 页
  • “您没有权限” 11页

由于需要考虑细微差别和通常措辞不当的标题,对于志愿者来说,链接到最相关的副本既困难又耗时。


它由什么组成?

此问答包含的条目旨在提供有关如何:

  • 解析错误信息结构
  • 了解错误意味着什么
  • 始终如一地重现(如适用)
  • 解决问题
  • 提供规范问答的链接(在可能的情况下)

目录

为了帮助您浏览不断增长的参考,请使用下面的目录:

  1. 一般错误
  2. 特定于服务的错误

这不是什么?

问答的范围仅限于普通(非平凡)。这不是:

  • 一个包罗万象的指南或“最佳实践”集合
  • 一般 ECMAScript 错误的参考
  • 气体文件
  • 资源列表(我们有一个标签维基

要添加什么?

添加条目时,请考虑以下事项:

  • 错误是否足够常见(参见“为什么”部分的示例)?
  • 该解决方案能否简明扼要地描述并适用于大多数情况?

Ole*_*ter 5

前言

答案提供了有关在使用任何 Google 服务(内置和高级)或 API 时可能遇到的一般错误的指南。有关特定于某些服务的错误,请参阅其他答案

返回参考


一般错误


信息

类型错误:无法property name here从中读取属性“ ”undefined (or null)

描述

该错误消息表明您正在尝试访问Object实例上的属性,但在运行时,变量实际持有的值是特殊数据类型undefined。通常,在访问对象的嵌套属性时会发生错误。

使用数值代替属性名称的此错误的变体表明Array预期实例为。由于 JavaScript 中的数组是对象,因此这里提到的所有内容也都适用于它们。

动态构造的对象有一种特殊情况,例如仅在特定上下文中可用的事件对象,例如向应用程序发出 HTTP 请求或通过时间或基于事件的触发器调用函数。

错误是TypeError因为它"object"是预期的,但"undefined"被接收

怎么修

  1. 使用默认值JavaScript 中的
    逻辑 OR ||运算符有一个有趣的属性,即如果左侧为falsy评估右侧。由于JS对象是truthy,并且undefinednull是falsy,就像表达式(myVar || {}).myProp[(myVar || [])[index]数组]将保证不会引发错误并且所述特性是至少undefined

    还可以提供默认值:(myVar || { myProp : 2 })保证访问默认myProp返回2。数组也是如此:(myVar || [1,2,3]).

  2. 检查类型
    对于特殊情况尤其如此, typeof 运算符结合if 语句比较运算符将允许函数在其指定上下文之外运行(即用于调试目的)或根据对象是否存在引入分支逻辑.

    可以控制检查的严格程度:

  • 松散(“未定义”): if(typeof myVar !== "undefined") { //do something; }
  • 严格(“仅限正确的对象”): if(typeof myVar === "object" && myVar) { //do stuff }

相关问答

  1. GAS项目的解析顺序作为问题的来源

信息

无法转换some valuedata type

描述

由于传递的参数类型与方法预期的不同,因此引发错误。导致错误的常见错误是将数字意外强制转换为 string

如何繁殖

function testConversionError() {
  const ss = SpreadsheetApp.getActiveSheet();
  ss.getRange("42.0",1);
}
Run Code Online (Sandbox Code Playgroud)

怎么修

确保错误消息中引用的值是文档要求的数据类型,并根据需要进行转换


信息

无法Service and method name从此上下文调用

描述

此错误发生在上下文不匹配时,并且特定于容器绑定脚本。导致错误的主要用例是尝试从另一种(即从电子表格)调用仅在一种文档类型(通常,getUi()因为它由多个服务共享)中可用的方法DocumentApp.getUi()

次要但也是突出的情况是调用服务的结果,该服务未明确允许自定义函数(通常是由特殊的 JSDoc 样式注释标记@customfunction并用作公式的函数)调用。

如何繁殖

对于绑定脚本上下文不匹配,请在与 Google Sheets(或 Google Docs 以外的任何内容)绑定的脚本项目中声明并运行此函数:

function testContextMismatch() {
  const doc = DocumentApp.getUi();
}
Run Code Online (Sandbox Code Playgroud)

请注意,调用 aDocumentApp.getActiveDocument()只会导致null不匹配,并且执行将成功

对于自定义函数,在任何单元格中使用下面声明的函数作为公式:

/**
 * @customfunction
 */
function testConversionError() {
  const ui = SpreadsheetApp.getUi();
  ui.alert(`UI is out of scope of custom function`);
}
Run Code Online (Sandbox Code Playgroud)

怎么修

  1. 通过更改调用方法的服务,可以轻松修复上下文不匹配。
  2. 无法使用定义函数来调用这些服务、使用自定义菜单或对话框

信息

找不到方法 Method name here

参数param names与方法签名不匹配method name

描述

这个错误对新手来说是一个众所周知的令人困惑的信息。它说的是在调用相关方法时传递的一个或多个参数中发生类型不匹配

没有与您调用它的方式相对应的签名方法,因此“未找到”

怎么修

这里唯一的解决方法是仔细阅读文档并检查参数的顺序和推断类型是否正确(使用具有自动完成功能的良好 IDE 会有所帮助)。但是,有时会出现问题,因为人们期望值是某种类型,而在运行时它是另一种类型。有几个技巧可以防止此类问题:

  1. 设置类型保护(typeof myVar === "string"和类似的)。
  2. 由于 JavaScript 是动态类型的,因此添加了一个验证器来动态修复类型

样本

function testConversionError() {
  const ss = SpreadsheetApp.getActiveSheet();
  ss.getRange("42.0",1);
}
Run Code Online (Sandbox Code Playgroud)


留言

您无权执行该操作

脚本无权执行该操作

描述

该错误表明所访问的 API 或服务之一缺乏来自用户的足够权限。每个在其文档中有授权部分的服务方法都需要至少一个范围被授权。

由于 GAS 本质上围绕 Google API 以方便开发,因此可以使用OAuth 2.0 API参考范围中列出的大多数范围,但如果在相应的文档中列出了一个范围,则最好使用它,因为存在一些不一致之处。

请注意,自定义函数在未经授权的情况下运行。从 Google 工作表单元格调用函数是导致此错误的最常见原因。

怎么修

如果从脚本编辑器运行调用服务的函数,系统会自动提示您使用相关范围对其进行授权。尽管对于快速手动测试很有用,但最好在应用程序清单 (appscript.json) 中明确设置范围。此外,如果打算发布应用程序,自动范围通常太广泛而无法通过审核

oauthScopes清单文件中的字段(View -> Show manifest file如果在代码编辑器中)应如下所示:

  "oauthScopes": [
    "https://www.googleapis.com/auth/script.container.ui",
    "https://www.googleapis.com/auth/userinfo.email",
    //etc
  ]
Run Code Online (Sandbox Code Playgroud)

对于自定义功能,您可以通过切换到从菜单或按钮调用该功能来修复它,因为无法授权自定义功能

对于那些开发编辑器 Add-ons 的人来说,这个错误意味着一种未处理的授权生命周期模式:在调用需要授权的服务之前必须中止,以防 auth 模式是AuthMode.NONE

相关原因及解决方法

  1. @OnlyCurrentDoc 限制脚本访问范围
  2. 范围自动检测

信息

参考错误:service name未定义

描述

最常见的原因是使用高级服务而不启用它。当启用这样的服务时,指定标识符下的变量被附加到开发人员可以直接引用的全局范围内。因此,当引用禁用的服务时,ReferenceError会抛出 a。

怎么修

转到“资源 -> 高级 Google 服务”菜单并启用引用的服务。请注意,标识符应等于引用的全局变量。更详细的解释,请阅读官方指南

如果没有引用任何高级服务,则错误指向正在引用的未声明变量。


信息

脚本完成但没有返回任何内容。

找不到脚本函数: doGet or doPost

描述

这本身不是错误(因为返回的 HTTP 响应代码是200并且执行被标记为成功,但通常被视为一个错误。尝试从浏览器发出请求/访问脚本时出现该消息部署为 Web 应用程序的脚本.

发生这种情况的主要原因有两个:

  1. 没有doGetdoPost触发功能
  2. 触发上述不返回一个HtmlOutputTextOutput实例

怎么修

对于第一个原因,只需提供一个doGetordoPost触发器(或两者)功能。其次,确保您的应用程序的所有路由都以创建TextOutputor结束HtmlOutput

//doGet returning HTML
function doGet(e) {
  return HtmlService.createHtmlOutput("<p>Some text</p>");
}

//doPost returning text
function doPost(e) {
  const { parameters } = e;
  const echoed = JSON.stringify(parameters);
  return ContentService.createTextOutput(echoed);
}
Run Code Online (Sandbox Code Playgroud)

请注意,应该声明一个触发器函数 - 将它们视为应用程序的入口点。

如果触发器依赖parameter/parameters来路由响应,请确保请求 URL 的结构为“ baseURL/exec? query”或“ baseURL/dev? query”,其中query包含要传递的参数

相关问答

  1. 声明触发器后重新部署

信息

很抱歉,发生服务器错误。请稍等,然后重试。

描述

这是最神秘的错误,几乎可以在任何服务的任何时候发生(尽管DriveApp使用情况特别容易受到影响)。该错误通常表明 Google 方面存在问题,该问题要么在几个小时/几天内消失,要么在此过程中得到修复。

怎么修

对此没有灵丹妙药,通常,除了在问题跟踪器上提交问题或联系支持(如果您有 GSuite 帐户)之外,您无能为力。在此之前,您可以尝试以下常见的补救措施:

  1. 对于绑定脚本 - 创建一个新文档并复制现有项目和数据。
  2. 切换到使用高级Drive 服务(始终记得先启用它)。
  3. 如果错误指向一行,则正则表达式可能存在问题

不要因为这个错误而大惊小怪 - 尝试定位受影响的代码、文件或为问题加注星标,然后继续


没有明显问题的语法错误

这个错误很可能是由于在使用已弃用的 V8 运行时(在编写 GAS 平台使用 V8时)时使用 ES6 语法(例如,箭头函数)引起的。

怎么修

打开“appscript.json”清单文件并检查是否runtimeVersion设置为"V8",否则更改它,否则删除任何ES6 功能


配额相关错误

有几个与强加于服务使用的配额相关的错误。谷歌有一个完整的列表,但作为一般经验法则,如果一条消息匹配“太多”模式,你可能已经超过了各自的配额。

最可能遇到的错误:

  • 服务调用次数过多: service name
  • 运行的脚本太多
  • 一天使用过多电脑时间的服务
  • 这个脚本有太多触发器

怎么修

在大多数情况下,唯一的解决办法是等到配额刷新或切换到另一个帐户(除非脚本部署为具有“以我的身份运行”权限的 Web 应用程序,在这种情况下,所有者的配额将在所有用户之间共享)。

引用当时的文件:

每日配额在 24 小时窗口结束时刷新;但是,此刷新的确切时间因用户而异。

请注意,某些服务(例如MailApp具有此类方法)getRemainingDailyQuota可以检查剩余配额。

在超过触发器的最大数量的情况下,可以通过getProjectTriggers()(或检查“我的触发器”选项卡)检查安装了多少个,并采取相应措施减少数量(例如,通过使用deleteTrigger(trigger)摆脱一些)。

相关规范问答

  1. 如何应用和刷新每日限制?
  2. “超过最大执行时间”问题
  3. 优化服务调用以减少执行时间

参考

  1. 如何使错误消息更有意义
  2. 调试自定义函数

  • @TheMaster - 不用担心,这个问答的原因是对看到不同风格的相同问题感到厌倦 - 我已经将答案制作为社区维基,所以请随意编辑,并感谢您支持这一努力。 (2认同)

归档时间:

查看次数:

4614 次

最近记录:

5 年,3 月 前