第三方 API

Google Ads 脚本的一项强大功能是能够与第三方 API 的数据和服务集成。

本指南介绍了以下概念,它们可以帮助您编写脚本以连接到其他服务:

  • 发出 HTTP 请求:如何使用 UrlFetchApp 访问外部 API。
  • 身份验证:我们介绍了一些常见的身份验证场景。
  • 解析响应:如何处理返回的 JSON 和 XML 数据。

使用 UrlFetchApp 提取数据

UrlFetchApp 提供了与第三方 API 交互所需的核心功能。

以下示例展示了如何从 OpenWeatherMap 获取天气数据。我们之所以选择 OpenWeatherMap,是因为其授权方案和 API 相对简单。

发出请求

OpenWeatherMap 文档指定了用于请求当前天气的格式,如下所示:

http://api.openweathermap.org/data/2.5/weather?q=[location]&apikey=[apikey]

该网址提供了我们的第一个授权示例:apikey 参数是必需的,其值对于每位用户都是唯一的。此密钥可通过注册获取。

注册后,使用该密钥的请求可发出如下:

const location = 'London,uk';
const apikey = 'da.......................81'; // Replace with your API key
const currentWeatherUrl = `http://api.openweathermap.org/data/2.5/weather?q=${location}&apiKey=${apiKey}`;
const response = UrlFetchApp.fetch(currentWeatherUrl);
console.log(response.getContentText());

执行此代码会生成一长串 JSON 文本,并将其写入 Google Ads 脚本中的日志记录窗口。

下一步是将其转换为可在脚本中使用的格式。

JSON 数据

许多 API 都提供 JSON 格式的响应。它表示 JavaScript 对象的简单序列化,此类对象、数组和基本类型可以字符串形式表示和传输。

如需将 JSON 字符串(例如从 OpenWeatherMap 返回的字符串)转换回 JavaScript 对象,请使用内置的 JSON.parse 方法。接着上面的示例继续:

const json = response.getContentText();
const weatherData = JSON.parse(json);
console.log(weatherData.name);
//  "London"

JSON.parse 方法可将字符串转换为具有 name 属性的对象。

如需详细了解如何处理不同格式的 API 响应,请参阅解析响应部分。

错误处理

在脚本中使用第三方 API 时,错误处理是一个重要的考虑因素,因为第三方 API 经常更改并生成意外的响应值,例如:

  • API 的网址或参数可能会在您不知情的情况下发生变化。
  • 您的 API 密钥(或其他用户凭据)可能会过期。
  • 响应的格式可能发生更改,恕不另行通知。

HTTP 状态代码

由于可能会出现意外响应,您应该检查 HTTP 状态代码。默认情况下,如果遇到 HTTP 错误代码,UrlFetchApp 会抛出异常。要更改此行为,需要传递可选参数,如以下示例所示:

const options = {
  muteHttpExceptions: true
}
const response = UrlFetchApp.fetch(url, options);
// Any status code greater or equal to 400 is either a client or server error.
if (response.getResponseCode() >= 400) {
  // Error encountered, send an email alert to the developer
  sendFailureEmail();
}

响应结构

当第三方 API 发生更改时,开发者通常不会立即注意到可能会影响其脚本的更改。例如,如果 OpenWeatherMap 示例中返回的 name 属性更改为 locationName,则使用此属性的脚本将失败。

因此,测试返回的结构是否符合预期会很有帮助,例如:

const weatherData = JSON.parse(json);
if (weatherData && weatherData.name) {
  console.log('Location is : ' + name);
} else {
  console.log('Data not in expected format');
}

使用 UrlFetchApp 使用 POST 数据

使用 OpenWeatherMap 的入门示例仅提取了数据。通常,不会在远程服务器上更改状态的 API 调用使用 HTTP GET 方法。

GET 方法是 UrlFetchApp 的默认方法。不过,某些 API 调用(例如调用发送短信的服务)将需要使用其他方法,如 POSTPUT

为了说明将 POST 调用与 UrlFetchApp 结合使用,以下示例演示了与协作消息传递应用 Slack 的集成,以便向 Slack 用户和群组发送 Slack 消息。

设置 Slack

本指南假定您已注册一个 Slack 帐号。

与上例中的 OpenWeatherMap 一样,用户需要获取令牌才能发送消息。Slack 提供了一个唯一的网址,供您向团队发送消息,该网址称为传入的网络钩子

点击添加传入 Webhook 集成并按照说明操作,以设置传入 Webhook。该进程应发出用于消息传递的网址。

发出 POST 请求

设置好传入 Webhook 后,若要发出 POST 请求,只需在传递给 UrlFetchApp.fetchoptions 参数中使用一些额外的属性即可:

  • method:如上所述,此属性默认为 GET,但我们在此处替换它并将其设置为 POST
  • payload:这是要作为 POST 请求的一部分发送到服务器的数据。在此示例中,Slack 需要一个序列化为 JSON 格式的对象(如 Slack 文档中所述)。为此,使用 JSON.stringify 方法,并将 Content-Type 设置为 application/json

      // Change the URL for the one issued to you from 'Setting up Slack'.
      const SLACK_URL = 'https://hooks.slack.com/services/AAAA/BBBB/CCCCCCCCCC';
      const slackMessage = {
        text: 'Hello, slack!'
      };
    
      const options = {
        method: 'POST',
        contentType: 'application/json',
        payload: JSON.stringify(slackMessage)
      };
      UrlFetchApp.fetch(SLACK_URL, options);
    

扩展的 Slack 示例

上面的示例展示了允许传入 Slack 消息的最低要求。详细示例介绍了如何创建广告系列效果报告并将其发送到某个组,以及一些格式和显示选项。

收到的消息

如需详细了解 Slack 消息,请参阅 Slack 文档中的消息格式

表单数据

上面的示例演示了如何使用 JSON 字符串作为 POST 请求的 payload 属性。

根据 payload 的格式,UrlFetchApp 采用不同的方法来构建 POST 请求:

  • payload 是字符串时,字符串参数将作为请求正文发送。
  • payload 是对象时,例如值的映射:

    {to: 'mail@example.com', subject:'Test', body:'Hello, World!'}
    

    键值对转换为表单数据:

    subject=Test&to=mail@example.com&body=Hello,+World!
    

    此外,请求的 Content-Type 标头也设置为 application/x-www-form-urlencoded

某些 API 在提交 POST 请求时需要使用表单数据,因此请务必注意,从 JavaScript 对象自动转换为表单数据

HTTP 基本身份验证

HTTP 基本身份验证是最简单的身份验证形式之一,被许多 API 使用。

身份验证的实现方式是将经过编码的用户名和密码附加到每个请求的 HTTP 标头中。

HTTP 基本身份验证

构建请求

要生成经过身份验证的请求,请按以下步骤操作:

  1. 使用英文冒号将用户名和密码连在一起,形成密码,例如 username:password
  2. 对口令进行 Base64 编码,例如,username:password 变为 dXNlcm5hbWU6cGFzc3dvcmQ=
  3. Authorization 标头以 Authorization: Basic <encoded passphrase> 的形式附加到请求

以下代码段说明了如何在 Google Ads 脚本中实现这一目标:

const USERNAME = 'your_username';
const PASSWORD = 'your_password';
const API_URL = 'http://<place_api_url_here>';

const authHeader = 'Basic ' + Utilities.base64Encode(USERNAME + ':' + PASSWORD);
const options = {
  headers: {Authorization: authHeader}
}
// Include 'options' object in every request
const response = UrlFetchApp.fetch(API_URL, options);

Plivo

Plivo 是一项服务,用于协助通过其 API 收发短信。此示例展示了如何发送消息。

  1. Plivo 注册。
  2. 示例脚本粘贴到 Google Ads 中的新脚本中。
  3. PLIVO_ACCOUNT_AUTHIDPLIVO_ACCOUNT_AUTHTOKEN 值替换为管理信息中心中的值。
  4. 按照脚本中指定的方式插入电子邮件地址,以便接收错误通知。
  5. 如需使用 Plivo,您必须购买号码或向试用帐号添加号码。添加可用于试用帐号的沙盒编号
  6. 添加将显示为发送者的号码和收件人的号码。
  7. 将脚本中的 PLIVO_SRC_PHONE_NUMBER 更新为刚刚注册的沙盒编号之一。这应包括国际国家/地区代码,例如为英国号码 447777123456

Twilio

Twilio 是另一种服务,用于通过其 API 收发短信。此示例展示了如何发送消息。

  1. Twillio 注册。
  2. 示例脚本粘贴到 Google Ads 中的新脚本中。
  3. TWILIO_ACCOUNT_SIDTWILIO_ACCOUNT_AUTHTOKEN 的值替换为帐号控制台页面上显示的值。
  4. TWILIO_SRC_PHONE_NUMBER 替换为信息中心中的号码,这是 Twilio 授权发送消息的号码。

OAuth 1.0

许多热门服务都使用 OAuth 进行身份验证。OAuth 有多种形式和版本

使用 HTTP 基本身份验证时,用户只有一个用户名和密码,OAuth 允许第三方应用使用特定于该第三方应用的凭据访问其帐号和数据。此外,访问范围也取决于该应用。

有关 OAuth 1.0 的背景信息,请参阅 OAuth 核心指南。请特别留意 6. 使用 OAuth 进行身份验证。在完整的三方模式 OAuth 1.0 中,流程如下:

  1. 应用(“使用方”)获取请求令牌。
  2. 用户对请求令牌进行授权。
  3. 应用使用请求令牌交换访问令牌。
  4. 对于所有后续资源请求,访问令牌用于已签名的请求。

如果第三方服务要在没有用户互动的情况下使用 OAuth 1.0(例如,按照 Google Ads 脚本的要求),将不可能执行第 1 步、第 2 步和第 3 步。因此,某些服务会从其配置控制台发出访问令牌,允许应用直接进入第 4 步。这称为单方模式 OAuth 1.0。

OAuth1

Google Ads 脚本中的 OAuth 1.0

对于 Google Ads 脚本,每个脚本通常解读为一个应用。通过服务的控制台/管理设置页面,通常需要执行以下操作:

  • 设置应用配置,以表示脚本。
  • 指定要为脚本扩展的权限。
  • 获取用于单方模式 OAuth 的使用方键值、使用方密钥、访问令牌和访问令牌。

OAuth 2.0

OAuth 2.0 在常用 API 中使用,旨在提供对用户数据的访问权限。给定第三方服务的帐号所有者向特定应用授予权限,以允许这些应用访问用户数据。其优势在于所有者:

  • 无需与应用共享其帐号凭据。
  • 可以控制哪些应用可单独访问数据以及在多大程度上可以访问数据。(例如,授予的访问权限可能是只读,也可能仅限于对一部分数据的访问权限。)

要在 Google Ads 脚本中使用已启用 OAuth 2.0 的服务,请按以下步骤操作:

在您的脚本之外

授权 Google Ads 脚本通过第三方 API 访问您的用户数据。在大多数情况下,这涉及在第三方服务的控制台中设置应用。此应用代表您的 Google Ads 脚本。

您可以指定应向 Google Ads 脚本应用授予哪些访问权限,并且通常会为其分配一个客户端 ID。这样,您就可以通过 OAuth 2 控制哪些应用可以访问您在第三方服务中的数据,还可以控制这些应用可以查看或修改该数据的哪些方面。

在您的脚本中

向远程服务器授权。根据服务器允许的授权类型,需要遵循一组不同的步骤(称为流程),但所有步骤最终都将引发一个访问令牌,该访问令牌将用于该会话的所有后续请求。

发出 API 请求。随每个请求传递访问令牌

授权流程

每种授权类型和相应流程都适用于不同的使用场景。例如,当用户参与交互式会话时,使用的是不同的流程,相比之下,应用需要在没有用户的情况下在后台运行。

API 提供方将决定他们接受哪些类型的授权,这将指导用户如何集成其 API。

实施步骤

对于所有不同的 OAuth 流程,目标是获取一个访问令牌,然后该访问令牌可用于会话的其余部分对请求进行身份验证。

示例库说明了如何针对每种不同的流类型进行身份验证。上述每种方法都会返回一个对象,用于获取并存储访问令牌,并为经过身份验证的请求提供便利。

一般使用模式如下:

// Authenticate using chosen flow type
const urlFetchObj = OAuth2.<flow method>(args);
// Make request(s) using obtained object.
const response1 = urlFetchObj.fetch(url1);
const response2 = urlFetchObj.fetch(url2, options);

授予客户端凭据

客户端凭据授权是 OAuth2 流程的一种较为简单的形式,采用这种流程时,应用会交换应用独有的 ID 和密钥,以换取限时访问令牌

客户端凭据

// Access token is obtained and cached.
const authUrlFetch = OAuth2.withClientCredentials(
    tokenUrl, clientId, clientSecret, optionalScope));
// Use access token in each request
const response = authUrlFetch.fetch(url);
// ... use response

刷新令牌授权

刷新令牌授权与客户端凭据授权类似,这是因为向服务器发出简单的请求就会返回一个可在会话中使用的访问令牌

刷新令牌

获取刷新令牌

与刷新令牌授权的不同之处在于,客户端凭据授权所需的详细信息来自应用配置(例如,在服务的控制台中),而刷新令牌是作为更复杂的流程(例如授权代码授权)的一部分授予的,该流程将需要用户互动:

授权代码

使用 OAuth Playground 获取刷新令牌

OAuth2 Playground 提供了一个界面,可让用户逐步完成授权代码授权以获取刷新令牌。

通过右上角的设置按钮,您可以定义要在 OAuth 流程中使用的所有参数,包括:

  • 授权端点:用作授权流程的起点。
  • 令牌端点:与刷新令牌搭配使用,以获取访问令牌。
  • 客户端 ID 和密钥:应用的凭据。

OAuth Playground

使用脚本获取刷新令牌

刷新令牌生成示例提供了基于脚本的替代方案来完成该流程。

刷新令牌使用情况

执行完初始授权后,服务便可以颁发刷新令牌,然后以类似于客户端凭据流程的方式使用该令牌。下面给出了两个示例:

const authUrlFetch = OAuth2.withRefreshToken(tokenUrl, clientId, clientSecret,
    refreshToken, optionalScope);
const response = authUrlFetch.fetch(url);
// ... use response

Search Ads 360 示例

Search Ads 360 就是一个可与刷新令牌配合使用的 API。 在此示例中,脚本会生成并返回报告。如需了解其他可执行操作的完整详情,请参阅 Search Ads 360 API 参考文档

创建脚本
  1. API 控制台中创建一个新项目,并按照 DoubleClick 指南中的流程操作,确保启用 DoubleClick Search API,以获取客户端 ID、客户端密钥和刷新令牌。
  2. 示例脚本粘贴到 Google Ads 中的新脚本中。
  3. 在代码清单下方,粘贴示例 OAuth2 库
  4. 修改脚本,使其包含正确的客户端 ID、客户端密钥和刷新令牌值。

Apps Script Execution API 示例

此示例展示了如何使用 Apps Script Execution API 在 Apps 脚本中执行函数。这样就可以从 Google Ads 脚本中调用 Apps 脚本。

创建 Apps 脚本脚本

创建新脚本。以下示例将列出云端硬盘中的 10 个文件:

function listFiles() {
  const limit = 10;
  const files = [];
  const fileIterator = DriveApp.getFiles();
  while (fileIterator.hasNext() && limit) {
    files.push(fileIterator.next().getName());
    limit--;
  }
  return files;
}
配置 Apps 脚本以便执行
  1. 保存脚本。
  2. 点击资源 > Cloud Platform 项目
  3. 点击项目名称,以转到 API 控制台。
  4. 前往 API 和服务
  5. 启用适当的 API,在本例中为 Drive APIApps Script Execution API
  6. 从菜单中的凭据项创建 OAuth 凭据。
  7. 返回您的脚本,通过选择发布 > 部署为 API 可执行文件发布要执行的脚本。
创建 Google Ads 脚本
  1. 示例脚本粘贴到 Google Ads 中的新脚本中。
  2. 此外,请将示例 OAuth2 库粘贴到代码列表下方。
  3. 修改脚本,使其包含正确的客户端 ID、客户端密钥和刷新令牌值。

服务账号

上述授权类型的替代方案是服务帐号概念。

服务帐号与上述帐号的不同之处在于,服务帐号不用于访问用户数据:身份验证后,服务帐号会代表应用(而不是以可能拥有相应项目的用户)的身份发出请求。例如,如果服务帐号要使用 Drive API 创建文件,文件将属于服务帐号,并且在默认情况下,项目所有者无法访问该文件。

Google Natural Language API 示例

Natural Language API 提供文本情感分析实体分析

以下示例说明了如何计算广告文字(包括标题或广告内容描述)的情感。它用于衡量消息的正面程度和消息规模:哪一个更好,是 We sales cakes 还是 We sales the best cakes in London. 立即购买!

设置脚本
  1. API 控制台中创建一个新项目
  2. 启用 Natural Language API
  3. 为项目启用结算功能。
  4. 创建服务帐号。下载凭据 JSON 文件。
  5. 示例脚本粘贴到 Google Ads 中的新脚本中。
  6. 此外,请将示例 OAuth2 库粘贴到代码列表下方。
  7. 替换必要的值:
    • serviceAccount:服务帐号的电子邮件地址,例如 xxxxx@yyyy.iam.gserviceaccount.com
    • key:创建服务帐号时下载的 JSON 文件中的密钥。开始时间:-----BEGIN PRIVATE KEY...,结束时间:...END PRIVATE KEY-----\n

API 响应

API 可以返回各种格式的数据。其中最值得注意的是 XML 和 JSON。

JSON

JSON 用作响应格式通常比 XML 更简单。但是,仍然会存在一些问题。

回复验证

通过调用 API 获得成功响应后,典型的下一步是使用 JSON.parse 将 JSON 字符串转换为 JavaScript 对象。此时,应当处理解析失败的情况:

const json = response.getContentText();
try {
  const data = JSON.parse(json);
  return data;
} catch(e) {
  // Parsing of JSON failed - handle error.
}

此外,如果 API 不在您的控制之下,请考虑响应的结构可能会发生变化,并且属性可能不再存在:

// Less good approach
// Assumes JSON was in form {"queryResponse": ...} when parsed.
const answer = data.queryResponse;

// Better approach
if (data && data.queryResponse) {
  const answer = data.queryResponse;
} else {
  // Format of API response has changed - alert developer or handle accordingly
}

XML

验证

XML 仍然是构建 API 的常用格式。您可以使用 XmlService parse 方法解析 API 调用的响应:

const responseText = response.getContentText();
try {
  const document = XmlService.parse(responseText);
} catch(e) {
  // Error in XML representation - handle accordingly.
}

虽然 XmlService.parse 会检测 XML 中的错误并相应地抛出异常,但它无法根据架构验证 XML。

根元素

如果 XML 文档已成功解析,系统会使用 getRootElement() 方法获取根元素:

const document = XmlService.parse(responseText);
const rootElement = document.getRootElement();

命名空间

以下示例使用了 Sportradar API 获取所选比赛的足球比赛结果。XML 响应采用以下格式:

<schedule xmlns="http://feed.elasticstats.com/schema/soccer/sr/v2/matches-schedule.xsd">
  <matches>
     ...
  </matches>
</schedule>

请注意如何在根元素中指定命名空间。因此,您必须执行以下操作:

  • 从文档中提取命名空间属性。
  • 遍历和访问子元素时,请使用此命名空间。

以下示例展示了如何访问上述文档代码段中的 <matches> 元素:

const document = XmlService.parse(xmlText);
const scheduleElement = document.getRootElement();
// The namespace is required for accessing child elements in the schema.
const namespace = scheduleElement.getNamespace();
const matchesElement = scheduleElement.getChild('matches', namespace);

获取值

以足球赛程中的样本为例:

<match status="..." category="..." ... >
  ...
</match>

可以检索属性,例如:

const status = matchElement.getAttribute('status').getValue();

可以使用 getText() 读取元素中包含的文本,但是,如果一个元素有多个文本子元素,则系统会将这些文本串联在一起。建议使用 getChildren(),并在可能存在多个文本子项的情况下遍历每个子项。

Sportradar 示例

这个完整的 Sportradar 示例说明了如何检索足球比赛的详细信息,尤其是英超联赛的比赛详情。Soccer API 是 Sportradar 提供的众多体育 Feed 中的一种。

设置 Sportradar 账号
  1. 前往 Sportradar 开发者网站
  2. 注册试用帐号
  3. 注册后,登录你的账号。
  4. 登录后,转到MyAccount

Sportradar 将不同的体育项目拆分成了不同的 API。例如,您可以购买对 Soccer API 的访问权限,而不是对 Tennis API 的访问权限。您创建的每个应用都可以有不同的关联运动项目和不同的键。

  1. 在“Applications”下,点击 Create a new Application(创建新应用)。为应用指定名称和说明,忽略网站字段。
  2. 仅选择 Issue a new key for Soccer Trial v2(针对欧洲足球试用版 v2 发布新密钥)。
  3. 点击 Register Application(注册应用)。

成功后,您应该会看到一个显示您的新 API 密钥的页面。

  1. 示例脚本粘贴到 Google Ads 中的新脚本中。
  2. 将列表中的 API 密钥替换为上面获取的密钥,然后修改电子邮件地址字段。

问题排查

使用第三方 API 时,多种原因可能会导致错误,例如:

  • 客户端以 API 不需要的格式向服务器发出请求。
  • 客户端期望的响应格式不同于所遇到的响应格式。
  • 客户端使用无效令牌或键,或留作占位符的值。
  • 客户端达到用量限额。
  • 客户端提供的参数无效。

在所有这些情况以及其他情况下,找出问题原因的第一步最好是检查导致错误的响应的详细信息。

解析响应

默认情况下,Google Ads 脚本引擎会抛出任何返回错误的响应(状态代码为 400 或更大)。

为了防止出现此行为并允许检查错误和错误消息,请将可选参数的 muteHttpExceptions 属性设置为 UrlFetchApp.fetch。例如:

const params = {
  muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, params);
if (response.getResponseCode() >= 400) {
  // ... inspect error details...
}

常见状态代码

  • 200 OK 表示成功。如果响应不包含预期数据,请考虑以下几点:

    • 某些 API 允许指定使用哪些字段和/或响应格式。如需了解详情,请参阅 API 文档。
    • 一个 API 可能有多个可以调用的资源。请参阅相关文档,确定其他资源是否可能更适用,以及该资源是否会返回您所需的数据。
    • 在编写代码后,API 可能已更改。如需详细说明,请参阅相关文档或开发者。
  • 400 Bad Request 通常表示发送到服务器的请求的格式或结构中有内容不正确。请检查请求并将其与 API 规范进行比较,以确保其符合预期。如需详细了解如何检查请求,请参阅检查请求

  • 401 Unauthorized 通常表示在未提供或未成功执行授权的情况下调用 API。

    • 如果 API 使用基本授权,请确保在请求中构建并提供 Authorization 标头。
    • 如果 API 使用 OAuth 2.0,请确保已获得访问令牌并以不记名令牌的形式提供。
    • 对于授权的任何其他变体,请确保为请求提供了必要的凭据。
  • 403 Forbidden 表示用户无权使用所请求的资源。

    • 确保用户已被授予必要的权限,例如在基于文件的请求中授予用户访问文件的权限。
  • 404 Not Found 表示请求的资源不存在。

    • 检查用于 API 端点的网址是否正确。
    • 如果要提取资源,请检查被引用的资源是否存在(例如,如果基于文件的 API 存在该文件)。

检查请求

当 API 响应指示请求的格式不正确(例如 400 状态代码)时,检查请求会非常有用。为便于检查请求,UrlFetchApp 具有 fetch() 方法的配套方法,名为 getRequest()

该方法不会向服务器发送请求,而是构建本应发送的请求,然后将其返回。这样,用户就可以检查请求的元素,确保请求看起来正确无误。

例如,如果请求中的表单数据由多个串联在一起的字符串组成,则错误可能在于您为生成该表单数据而创建的函数。简而言之:

const request = UrlFetchApp.getRequest(url, params);
console.log(request);
// Now make the fetch:
const response = UrlFetchApp.fetch(url, params);
// ...

可让您检查请求的元素

日志请求和响应

为了帮助您检查对第三方 API 的请求和响应的整个检查过程,可使用以下辅助函数来直接替代 UrlFetchApp.fetch(),以便记录请求和响应。

  1. 将代码中的所有 UrlFetchApp.fetch() 实例替换为 logUrlFetch()

  2. 将以下函数添加到脚本末尾。

    function logUrlFetch(url, opt_params) {
      const params = opt_params || {};
      params.muteHttpExceptions = true;
      const request = UrlFetchApp.getRequest(url, params);
      console.log('Request:       >>> ' + JSON.stringify(request));
      const response = UrlFetchApp.fetch(url, params);
      console.log('Response Code: <<< ' + response.getResponseCode());
      console.log('Response text: <<< ' + response.getContentText());
      if (response.getResponseCode() >= 400) {
        throw Error('Error in response: ' + response);
      }
      return response;
    }
    

执行脚本时,所有请求和响应的详细信息都会记录到控制台中,使调试变得更加容易。