UrlFetchApp 请求在菜单功能中失败,但在自定义功能中失败(连接到外部 REST API)

SAA*_*AAD 3 javascript rest urlfetch google-apps-script binance

我正在使用以下函数使用 Google Apps 脚本连接到外部 API (Binance) 以检索 JSON 数组(市场价格)。这个简单的查询 url 在浏览器中工作正常(不需要 API 密钥):

function getMyArray() {
  var url ="https://api.binance.com/api/v3/ticker/price"; // works perfectly in browser
  var params =  {"method"  : "get",  "muteHttpExceptions":true };  
  var response = UrlFetchApp.fetch(url, params);
  var array = JSON.parse(response.getContentText());
  
  return array;
}
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试在 Google Apps Script 中运行该函数时,情况就不同了:

  1. 脚本编辑器:在脚本编辑器中运行简单实用,但我收到403 error“请求被阻止”
  2. 菜单功能:从添加到电子表格 UI 的菜单项中调用该功能 => 相同403 error
  3. 自定义函数:编辑任何单元格并键入=getMyArray()=> 请求有效,我可以使用 Logger 跟踪数组

为什么我的简单请求在从菜单或脚本编辑器调用时被阻止,是否可以更改?谢谢

Tan*_*ike 5

UrlFetchApp自定义函数和脚本编辑器使用时,我认为区别在于是否使用IPv6,而每次运行时都会更改IPv4的地址。在这种情况下,脚本编辑器和自定义菜单的结果是相同的。我认为这可能是您的问题的原因。但我不确定我的猜测是否正确。所以,在这个答案中,我想提出以下解决方法。

  1. =getMyArray()使用脚本将公式放入单元格。
    • 通过这种方式,该值被检索到单元格中。
  2. 使用脚本从单元格中检索值。
  3. 清除放置公式。

通过这种流程,我认为您的目标可以实现。

示例脚本如下。

示例脚本:

在此脚本中,作为测试,=getMyArray()将放在活动工作表上的单元格“A1”中,并从单元格中检索值。当您使用它时,请main()在脚本编辑器和自定义菜单中运行该功能。通过这种方式,可以将值检索到array.

function getMyArray() {
  var url = "https://api.binance.com/api/v3/ticker/price";
  var params =  {"method": "get", "muteHttpExceptions": true};
  var response = UrlFetchApp.fetch(url, params);
  return response.getContentText();
}

// Please run this function by the script editor and the custom menu.
function main() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var range = sheet.getRange("A1");
  range.setFormula("=getMyArray()");
  SpreadsheetApp.flush();
  var value = range.getValue();
  range.clearContent();
  var array = JSON.parse(value);
  console.log(array)
}
Run Code Online (Sandbox Code Playgroud)

参考:

添加:

来自的响应值https://httpbin.org/get如下。

用于测试的示例脚本:

function sample() {
  var url = "https://httpbin.org/get";
  var res = UrlFetchApp.fetch(url);
  console.log(res.getContentText())
  return res.getContentText();
}
Run Code Online (Sandbox Code Playgroud)

结果:

模式 1. 使用脚本编辑器运行脚本。
{
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip,deflate,br", 
    "Host": "httpbin.org", 
    "User-Agent": "Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; +https://script.google.com; id: ###)", 
    "X-Amzn-Trace-Id": "Root=###"
  }, 
  "origin": "### IPV6 ###, ### IPV4 ###", // or "### IPV4 ###, ### IPV4 ###"
  "url": "https://httpbin.org/get"
}
Run Code Online (Sandbox Code Playgroud)
  • 当您使用 IPV6 时,origin"### IPV6 ###, ### IPV4 ###". 但是当您使用 IPV4 时,origin"### IPV4 ###, ### IPV4 ###".
  • 在这种情况下,无法从 中检索到正确的值https://api.binance.com/api/v3/ticker/price
模式 2. 脚本使用自定义函数运行。

在这种情况下,=sample()被放入一个单元格并检索该值。

{
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip,deflate,br", 
    "Host": "httpbin.org", 
    "User-Agent": "Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; +https://script.google.com; id: ###)", 
    "X-Amzn-Trace-Id": "Root=###"
  }, 
  "origin": "### IPV4 ###", 
  "url": "https://httpbin.org/get"
}
Run Code Online (Sandbox Code Playgroud)
  • 在这种情况下,可以从 中检索正确的值https://api.binance.com/api/v3/ticker/price
模式 3. 脚本与 OnEdit 事件触发器一起运行。

UrlFetchApp与自定义函数中使用,无需授权。但是当UrlFetchApp与OnEdit事件触发器一起使用时,需要授权的可安装触发器。我认为此授权可能会出现此问题。所以我比较了这个。

UrlFetchApp与可安装OnEdit事件触发器所使用的,下面的结果被检索。

{
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip,deflate,br", 
    "Host": "httpbin.org", 
    "User-Agent": "Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; +https://script.google.com; id: ###)", 
    "X-Amzn-Trace-Id": "Root=###"
  }, 
  "origin": "### IPV4 ###", 
  "url": "https://httpbin.org/get"
}
Run Code Online (Sandbox Code Playgroud)
  • 该结果与上述模式 2 相同。
  • 在这种情况下,可以从 中检索正确的值https://api.binance.com/api/v3/ticker/price

结果:

  • User-Agent所有模式的标题都相同。
  • 从模式二和模式三来看,与谷歌端的授权无关。
  • 当检索到带有 IPV4 的 WHOIS 时,返回相同的结果。
    • origin是 时"### IPV4 ###, ### IPV4 ###",第二个 IPV4 是 Google 的 IP 地址。

从上面的结果来看,所有模式的不同在于 的值origin是 1 还是 2。