【问题标题】:doPost(e) does not trigger onChange(e) - Trigger On Change event in Google SpreadsheetdoPost(e) 不触发 onChange(e) - 在 Google 电子表格中触发更改事件
【发布时间】:2018-06-24 16:18:32
【问题描述】:

我有一个非常简单的 doPost(e) 脚本项目,它用作 webhook 端点。它只是将接收到的 JSON 有效负载记录到目标电子表格的 A2 单元格中。在目标电子表格中,我有一个 onChange(e) 触发器,它将此有效负载传递给外部 API。虽然在运行时没有错误,但我的 onChange(e) 脚本根本没有被触发。如果我剪切/粘贴工作表上的单元格内容,onChange(e) 就会正确触发。

在 Google Developers 页面 here 中,提到了一些限制,但据说这些限制不适用于 doGet(e) 和 doPost(e)。

我错过了什么?

这是我的 doPost 代码:

var SHEETID = "my_sheetID_here";

function doPost(e) {
  try {
    var data = JSON.parse(e.postData.contents);
    var sSht = SpreadsheetApp.openById(SHEETID);
    var sht = sSht.getSheetByName("TEMP");
    sht.getRange("A2").setValue(e.postData.contents);

    return ContentService    // return json success results
    .createTextOutput(
      JSON.stringify({"result":"success",
                  "data": JSON.stringify(data) }))
    .setMimeType(ContentService.MimeType.JSON);
  } catch (e) {
    MailApp.sendEmail("xx@xx.com,yy@xx.com", "FireStation Webhook Error Occured!", 
      "\r\nMessage: " + e.message
      + "\r\nFile: " + e.fileName
      + "\r\nLine: " + e.lineNumber);
    e = (typeof e === 'string') ? new Error(e) : e;
    Logger.severe('%s: %s (line %s, file "%s"). Stack: "%s" . While processing %s.',e.name||'', 
           e.message||'', e.lineNumber||'', e.fileName||'', e.stack||'', processingMessage||'');
    throw e;
  }
}

这是我在目标表中的 onChange(e) 代码:

function onChange(e) {
  try {
    var sheet = e.source.getActiveSheet();
    var sheetname = sheet.getName();
    Logger.log("Sheetname: "+sheetname);
    if (sheetname === "TEMP" && sheet.getRange("A2").getValue() !== "") {
      var payload = sheet.getRange("A2").getValue();
      var URL = "my_external_api_URL_here";
      var options =
      {
        "method"  : "POST",
        "payload" : payload,   
        "followRedirects" : true,
        "muteHttpExceptions": true
      };
      var result = UrlFetchApp.fetch(URL, options);
      Logger.log("HTTP Response: "+result.getResponseCode())
    }
  } catch (e) {
    MailApp.sendEmail("xx@xx.com,yy@xx.com", "FireStation Template GAS Error Occured!", 
      "\r\nMessage: " + e.message
      + "\r\nFile: " + e.fileName
      + "\r\nLine: " + e.lineNumber);
    e = (typeof e === 'string') ? new Error(e) : e;
    Logger.severe('%s: %s (line %s, file "%s"). Stack: "%s" . While processing %s.',e.name||'', 
           e.message||'', e.lineNumber||'', e.fileName||'', e.stack||'', processingMessage||'');
    throw e;
  }
}

【问题讨论】:

  • Apps 脚本触发器仅由“用户在键盘上”操作按时间(时间驱动)触发
  • 正如您提到的,某些限制不适用于doGetdoPost。另请注意,onChange 不是这两者。您可以推断的是,通过调用 doGet/Post 启动的 Apps 脚本 session 将能够运行超过 30 秒等(仍然取决于您使用的任何用户权限)。如果您需要从您的 webapp 代码中激活 onChange,则只需显式调用它即可。
  • 正如@Sandy Good 在我之前所说的那样,而不是使用内置的表格服务,即 SpreadsheetApp.openById(sheetid)Range.setValue() i>,使用 Sheets API 版本 4 解决了问题并在目标电子表格上触发 onChange(e)。请注意,此解决方案需要从开发者控制台启用 Advanced Google Services/Sheet API
  • 您应该在您的解决方案中发布答案。它与我的解决方案不同,因此这是一个有效的答案。即使您将我的答案标记为正确,它也可能是首选答案。你可能会得到你的答案的赞成票,这会给你加分。人们通常不会回答自己的问题,但在这种情况下这是合理的。

标签: javascript google-apps-script google-sheets triggers onchange


【解决方案1】:

Sheets API 可用于触发“更改时”事件。不要使用setValues(array)。删除该代码并添加一个函数以将值写入电子表格。

您可能需要在 appsscript.json 文件(清单文件)中设置范围。

清单 (appsscript.json) 文件

{
  "timeZone": "America/New_York",
  "dependencies": {
  },
  "webapp": {
    "access": "MYSELF",
    "executeAs": "USER_DEPLOYING"
  },
  "exceptionLogging": "STACKDRIVER",
  "oauthScopes": ["https://www.googleapis.com/auth/drive",
                  "https://www.googleapis.com/auth/script.external_request"]
}

如果您正在使用其他范围,请在“文件”“项目属性”和“范围”选项卡中找到它们。将它们复制出来并将它们放在 appsscript.json 文件中,以保持相同的范围。

您的代码已修改:

function doPost(e) {
  try {
    var data = JSON.parse(e.postData.contents);

    writeToSheet({shName:"TEMP",ssFileID:SHEETID,data:data});//Write data to sheet using API

    return ContentService    // return json success results
    .createTextOutput(
      JSON.stringify({"result":"success",
                  "data": JSON.stringify(data) }))
    .setMimeType(ContentService.MimeType.JSON);
  } catch (e) {

    //code . . . .
}

新功能:

使用带有 valueInputOption=USER_ENTERED 选项的 Sheets API v4 的函数:

function writeToSheet(po) {
  var id,options,range,response,sh,targetSheetName,ss,url,values;

  targetSheetName = po.shName;
  id = po.ssFileID;

  range = targetSheetName + "!A2:A2";

  values = {values: [[po.data]]}; 

  url = "https://sheets.googleapis.com/v4/spreadsheets/" +
    id + "/values/" + range + ":append?valueInputOption=USER_ENTERED";

  options = {
    "method":"post",
    "muteHttpExceptions": true,
    "headers": {
      "Authorization": "Bearer " + ScriptApp.getOAuthToken()
    },
    "contentType": "application/json", 
    "payload": JSON.stringify(values) 
  }

  response = UrlFetchApp.fetch(url,options)
  response = JSON.parse(response);

  Logger.log('response ' + JSON.stringify(response))
}

【讨论】:

  • 非常感谢桑迪...我也发现了这一点并更新了我的查询!谢谢
【解决方案2】:

解决方案

不使用内置的表格服务,即 SpreadsheetApp.openById(sheetid)Range.setValue(),使用 Sheets API version 4 可以解决问题并触发 onChange (e) 在目标电子表格上。请注意,此解决方案需要从开发者控制台启用 Advanced Google Services/Sheet API。

这是我的 doPost(e) 调用的最新版本,它运行良好:

var SHEETID = "my_sheet_id_here";

function doPost(e) {
  try {
    var data = e.postData.contents;
    var rowValues = [
      [data,""],
    ];

    var request = {
      'valueInputOption': 'USER_ENTERED',
      'data': [
        {
          "range": "TEMP!A2:B2",
          "majorDimension": "ROWS",
          "values": rowValues,
        },
      ],
    };

    var response = Sheets.Spreadsheets.Values.batchUpdate(request, SHEETID);

    return ContentService    // return json success results
    .createTextOutput(
      JSON.stringify({"result":"success",
                  "data": JSON.stringify(data) }))
    .setMimeType(ContentService.MimeType.JSON);
  } catch (e) {
    MailApp.sendEmail("levent@able3ventures.com,alkio@able3ventures.com", "FireStation Webhook Error Occured!", 
      "\r\nMessage: " + e.message
      + "\r\nFile: " + e.fileName
      + "\r\nLine: " + e.lineNumber);
      e = (typeof e === 'string') ? new Error(e) : e;
      Logger.severe('%s: %s (line %s, file "%s"). Stack: "%s" . While processing %s.',e.name||'', 
           e.message||'', e.lineNumber||'', e.fileName||'', e.stack||'', processingMessage||'');
      throw e;
  }
}

【讨论】:

    猜你喜欢
    • 2014-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多