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

Google Apps Script触发器调用外部API返回401,手动运行正常

问题:Google Apps Script触发器调用Entire Recruit API返回401错误

我正在用Google Apps Script访问Entire Recruit API。手动运行pullTrigger函数时,getTokenFromAPI和后续的getShiftsBear、getMembersBear、getClientsBear接口都返回200;但使用时间触发器、onFormSubmit/OnEdit触发器运行时,只有getTokenFromAPI返回200,其余接口全部返回401。

想请教:

  1. 为什么触发器执行会出现这个问题?
  2. 是否需要使用异步函数?
  3. API文档提到要注册IP,但开发者表示未启用该限制,那是否需要借助Google Cloud才能带认证访问外部API?

触发器调用的函数代码

function pullTrigger(){
  SpreadsheetApp.openByUrl(dataURL);
  let token = getTokenFromAPI();
  Logger.log("Starting");
  SpreadsheetApp.flush();
  Utilities.sleep(3000);
  getShiftsBear(token);
  SpreadsheetApp.flush();
  Utilities.sleep(3000);
  getMembersBear(token);
  SpreadsheetApp.flush();
  Utilities.sleep(3000);
  getClientsBear(token);
  SpreadsheetApp.flush();
  Logger.log("Concluded");
}

接口函数示例(getShiftsBear)

function getShiftsBear(token){
  Logger.log('Bearer Auth in header');

  //var url3 = 'http://developers.entirerecruit.com/recruit-out/v1.0/GetShiftsByShiftDate?ShiftFromDate=2022-08-01&ShiftToDate=2022-08-07&Show_TimesheetVerified=false&$count=true'; //all shifts
  let url3 = urlBase;
  let fromDate = getTodayDate();
  let toDate = getTomorrowDate(); //need a way to get dates in
  let para = 'GetShiftsByShiftDate?ShiftFromDate='+ fromDate +'&ShiftToDate=' + toDate + '&Show_TimesheetVerified=false&$count=true' //combines date with URL - all shifts
  url3 = url3 + para;
  console.log("the url is - " + url3);

  var auth = 'Bearer ' + token;
  console.log(auth);

  var response = UrlFetchApp.fetch(url3, {
    method: 'GET',
     headers: {
      'Authorization': auth
      },
     muteHttpExceptions: true
   });
  Logger.log('Response Code: ' + response.getResponseCode());
   if (responseCodeEscape(response.getResponseCode()) == 0){
     Logger.log("fail " + response.getResponseCode());
     return;
   } 

   var content = response.getContentText();
   //console.log(content);
   var json = JSON.parse(content);
   //console.log(json["value"]);  
   json = json["value"];

   var keys = []

   for(var key in json){ 
     var arr = [key , json[key]["ShiftCtrlNumber"],json[key]["ServiceId"],json[key]["DeliveryId"],json[key]["ServiceName"],json[key]["DeliveryName"],json[key]["ShiftOrderedDate"],json[key]["ShiftDate"],json[key]["ShiftDay"],json[key]["ShiftType"],json[key]["Start"],json[key]["End"],json[key]["QualificationCode"],json[key]["ExpertiseCode"],json[key]["EmployeeId"],json[key]["OfficeName"],json[key]["PostCode"],json[key]["PriorityID"],json[key]["PriorityName"],json[key]["QualificationCode"],json[key]["State"],json[key]["StatusCode"],json[key]["StatusDescription"],json[key]["FirstName"],json[key]["LastName"],json[key]["IsBooked"],json[key]["IsVerified"],json[key]["Break"],json[key]["WkdHrs"],json[key]["StatusCode"],json[key]["StatusDescription"],json[key]["OfficeID"],json[key]["OfficeName"],json[key]["ProfessionalCode"],json[key]["ProfessionalName"],json[key]["AuthorizedPersonName"],json[key]["BookingRatio"],json[key]["OrderNo"],json[key]["BookedBy"],json[key]["LastUpdatedOn"]]   
     keys.push(arr); 
   }

   var ss = SpreadsheetApp.openByUrl(dataURL).getSheetByName("shifts_dump");
   var headers =ss.getRange('1:2').getValues();
   ss.clear();
   ss.getRange('1:2').setValues(headers);
   console.log(keys.length);
   if (keys.length > 0){
     ss.getRange(2,2,keys.length,40).setValues(keys);
   }
}

问题分析与解答

1. 触发器执行返回401的核心原因

手动运行和触发器运行的执行上下文完全不同:

  • 手动运行时,脚本以你的个人账号权限执行,UrlFetchApp请求的IP是你本地设备的IP,或是Google为个人会话分配的专属IP。
  • 触发器(时间/表单/编辑触发器)运行时,脚本在Google服务器上执行,使用的是Google云IP池中的IP。

虽然开发者声称未启用IP限制,但很多API的token会隐性绑定请求IP(用于防盗用)。你手动获取的token基于本地IP生成,触发器用Google服务器IP请求时,token的IP校验失败,直接返回401。

2. 是否需要异步函数?

不需要。当前的同步调用逻辑没有问题,Utilities.sleep的间隔设置也合理,401错误和异步调用无关,核心是token的有效性问题。

3. 是否需要借助Google Cloud?

不需要额外依赖Google Cloud,但需要调整token的获取逻辑:

  • 不要在函数开头只获取一次token,而是在每个接口请求前重新获取token。因为触发器运行的IP和手动运行不同,之前获取的token在新IP环境下无效。
  • 检查getTokenFromAPI的实现,确保它在触发器上下文里能正常获取适配当前IP的有效token。

额外排查点

  • 打印触发器运行时获取的token和手动运行的token,对比是否一致。如果一致,说明API确实存在隐性IP校验;如果不一致,检查getTokenFromAPI是否依赖了只有手动运行时才有的缓存或属性。
  • 在getShiftsBear中打印完整请求头,确认Authorization头正确携带了token,没有拼写错误(比如Bearer后面的空格是否存在)。

内容的提问来源于stack exchange,提问作者Simon Murray

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:18:27