JavaScript 对象模型

本页面适用于 ApigeeApigee Hybrid

查看 Apigee Edge 文档。

本主题讨论了 Apigee JavaScript 对象模型。如果您打算使用 JavaScript 政策将自定义 JavaScript 添加到 API 代理,则必须了解此模型。

JavaScript 对象模型简介

JavaScript 对象模型定义具有关联属性的对象,这些对象可供在 Apigee 代理流中执行的 JavaScript 代码使用。可以使用 JavaScript 政策将此自定义代码附加到 API 代理流。

此模型定义的对象的范围在 API 代理流内,这意味着某些对象和属性仅在流程的特定点可用。当 JavaScript 执行时,系统会为执行创建一个范围。在该范围内创建以下对象引用:

  • context:提供消息上下文访问权限的对象
  • request:允许访问请求对象的简便方法
  • response:允许访问响应对象的简写
  • crypto:提供各种哈希函数
  • print:用于发出输出的函数
  • properties:允许读取政策中的配置属性

上下文对象

context 对象具有全局范围。它在 API 代理流中的任何位置都可用。它有四个子对象:proxyRequestproxyResponsetargetRequesttargetResponse。这些子对象仅限于环境请求和响应,包括代理请求和响应以及目标请求和响应。例如,如果 JavaScript 政策在流的代理端点部分执行,则 context.proxyRequestcontext.proxyResponse 对象都在范围内。如果 JavaScript 在目标流中运行,则 context.targetRequestcontext.targetResponse 对象在范围内。

context 对象还具有属性和方法,本主题对此进行了详细说明。例如,以下 JavaScript 代码示例使用 context.flow 属性,并对 context 调用 get/setVariable() 方法。

if (context.flow=="PROXY_REQ_FLOW") {
     var username = context.getVariable("request.formparam.user");
     context.setVariable("USER.name", username);
}

这些方法直接与流变量进行交互。context.flow 属性值是当前的流范围。在代理请求流中,它被设置为常量 PROXY_REQ_FLOW。如果目标响应流中,它被设置为 TARGET_RESP_FLOW。此常量对于执行特定于范围的代码十分方便。您可以通过 getter 获取流变量,并通过 setter 设置流变量。这些变量通常在代理流中可用,并且可供其他政策使用。

如需了解详情和查看示例,请参阅上下文对象参考

加密对象

加密对象为 JavaScript 对象模型添加了基本的高性能加密支持。如需了解详情和查看示例,请参阅加密对象参考

request 和 response 对象

requestresponse 对象是环境请求和响应的“简写”,可以是代理请求和响应,也可以是目标请求和响应。这些变量引用的对象取决于执行 JavaScript 政策的上下文。如果 JavaScript 在代理端点流中运行,则请求和响应变量引用的是 context.proxyRequestcontext.proxyResponse。如果 JavaScript 在目标流中运行,则变量引用的是 context.targetRequestcontext.targetResponse

JavaScript 对象模型包含一个 print() 函数,您可以使用该函数将调试信息输出到 Apigee 调试工具。请参阅使用 JavaScript print() 语句进行调试

properties 对象

在政策配置中使用 Properties 元素时,JavaScript 代码可以使用 properties 变量访问这些属性的值。

例如,如果您的 JavaScript 配置包含下面的内容:

<Javascript name='JS-1' >
  <Properties>
    <Property name="number">8675309</Property>
    <Property name="firstname">Jenny</Property>
  </Properties>
  <ResourceURL>jsc://my-code.js</ResourceURL>
</Javascript>

那么,您可以在 my-code.js 中输出以下内容:

  print(properties.firstname);  // prints Jenny
  print(properties.number);  // 8675309

实际上,配置可以允许代码在不同的环境、不同的时刻或出于任何原因运行时表现出不同的行为。

例如,下面的代码指定了 JavaScript 应将信息发送到的“变量名称”及输出样式:

<Javascript name='JS-2' >
  <Properties>
    <Property name="output">my_output_variable</Property>
    <Property name="prettyPrint">true</Property>
  </Properties>
  <ResourceURL>jsc://emit-results.js</ResourceURL>
</Javascript>
之后,在 emit-results.js 中,代码便可以执行以下操作:
var result = { prop1: "something", prop2 : "something else" } ;
if (properties.prettyPrint == "true") {
  context.setVariable(properties.output, JSON.stringify(result, null, 2));
}
else {
  context.setVariable(properties.output, JSON.stringify(result));
}

加密对象参考

加密对象可让您在 JavaScript 中执行基本加密哈希函数。

加密对象具有全局范围。它在 API 代理流中的任何位置都可用。加密支持使用以下哈希对象:

  • SHA-1
  • SHA256
  • SHA512
  • MD5

使用 SHA-1 对象

您可以创建和更新 SHA-1 对象,并将它们转换为十六进制和 base64 值。

创建新的 SHA-1 对象

var _sha1 = crypto.getSHA1();

更新 SHA-1 对象

语法

_sha1.update(value);

参数

  • value -(字符串)任何字符串值。

示例

更新 SHA-1 对象:

_sha1.update("salt_value");

_sha1.update("some text");

以十六进制字符串的形式返回 SHA-1 对象

var _hashed_token = _sha1.digest();

以 base64 字符串的形式返回 SHA-1 对象

var _hashed_token = _sha1.digest64();

使用 SHA-256 对象

您可以创建和更新 SHA-256 对象,并将它们转换为十六进制和 base64 值。

创建新的 SHA-256 对象

var _sha256 = crypto.getSHA256();

更新 SHA-256 对象

语法

_sha256.update(value);

参数

  • value -(字符串)任何字符串值。

示例

更新 SHA-256 对象:

_sha256.update("salt_value");

_sha256.update("some text");

以十六进制字符串的形式返回 SHA-256 对象

var _hashed_token = _sha256.digest();

以 base64 字符串的形式返回 SHA-256 对象

var _hashed_token = _sha256.digest64();

使用 SHA-512 对象

您可以创建和更新 SHA-512 对象,并将它们转换为十六进制和 base64 值。

创建新的 SHA-512 对象

var _sha512 = crypto.getSHA512();

更新 SHA-512 对象

语法

_sha512.update(value);

参数

  • value -(字符串)任何字符串值。

示例

更新 SHA-512 对象:

_sha512.update("salt_value");

_sha512.update("some text");

以十六进制字符串的形式返回 SHA-512 对象

var _hashed_token = _sha512.digest();

以 base64 字符串的形式返回 SHA-512 对象

var _hashed_token = _sha512.digest64();

使用 MD5 对象

您可以创建和更新 MD5 对象,并将它们转换为十六进制和 base64 值。

创建新的 MD5 对象

var _md5 = crypto.getMD5();

更新 MD5 对象

语法

_md5.update(value);

参数

  • value -(字符串)任何字符串值。

示例

更新 MD5 对象:

_md5.update("salt_value");

_md5.update("some text");

以十六进制字符串的形式返回 MD5 对象

var _hashed_token = _md5.digest();

以 base64 字符串的形式返回 MD5 对象

var _hashed_token = _md5.digest64();

加密日期/时间支持

加密对象支持日期/时间格式模式。

crypto.dateFormat()

以字符串格式返回日期。

语法

crypto.dateFormat(format, [timezone], [time])

参数

  • format -(字符串)此参数的底层实现为 java.text.SimpleDateFormat。例如:YYYY-MM-DD HH:mm:ss.SSS
  • timezone -(字符串,可选)此参数的底层实现为 java.util.TimeZone。此参数相同 默认值:UTC
  • time -(数字,可选)要设置格式的 Unix 时间戳值。默认值:当前时间

示例

获取当前时间,精确到毫秒:

var _now = crypto.dateFormat('YYYY-MM-DD HH:mm:ss.SSS');

获取太平洋时区的当前时间:

var _pst = crypto.dateFormat('YYYY-MM-DD HH:mm:ss.SSS','PST');

获取从现在开始的 10 秒的值:

var _timeNow = Number(context.getVariable('system.timestamp'));
var tenSeconds = crypto.dateFormat('YYYY-MM-DD HH:mm:ss.SSS','PST', _timeNow + 10 * 1000);

以下是更多示例。另请参阅 java.text.SimpleDateFormat 文档。

var _pst = crypto.dateFormat('M');
var _pst = crypto.dateFormat('EEE, d MMM yyyy HH:mm:ss Z');
var _pst = crypto.dateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

使用 WS-Security 和 X.509 证书保护 SOAP 文档的安全

使用 WS-Security 和 RSA/X.509 数字签名保护 SOAP 文档。

crypto.wsSecRsaSign()

对 SOAP 文档进行签名,并返回签名后的载荷。

语法

crypto.wsSecRsaSign(payload, options)

参数

  • 载荷 - (String) 要签名的 SOAP 文档。
  • options - (Object) 数字签名的配置选项。下表列出了可用的配置选项。所有选项值都可以是字面量字符串或消息模板,使用模板字符 '{''}' 表示。
    名称 是否必需? 说明
    certificate 必需 与私钥匹配的证书,采用 PEM 格式。
    private_key 必需 包含 PEM 格式的私钥的流变量。
    c14_inclusive_elements 可选 用于向 CanonicalizationMethod 元素添加 InclusiveElements 元素的命名空间 URI(而非前缀)的英文逗号分隔列表。
    confirmation 可选 以下项之一:
    • SignatureConfirmation 元素中要签名的签名值列表。如果不存在具有指定值的 SignatureConfirmation 元素,系统会注入该元素。
    • \*all\* 字符串,表示来源文档中的任何现有 SignatureConfirmation 元素都将签名。
    • 空字符串,表示注入一个空的 SignatureConfirmation 元素。
    这些确认签名是 elements-to-sign 中指定的元素之外的元素。
    digest_method 可选 摘要算法。有效值为 sha1sha256。 默认值为 sha256
    ds_prefix 可选 要用作命名空间前缀的简单字符串。
    elements_to_sign 可选 要签名的元素的 XPath 表达式数组(例如,["soapenv:Body"])。
    expiry 可选 要注入到 TimestampExpires 元素中的值。 输入 120s、10m 和 4d 等值,分别表示 120 秒、10 分钟和 4 天。默认值为永不过期。
    ignore_security_header_placement 可选 一个布尔值,用于指定是否检查未签名载荷中任何现有 Security 标头的位置。提供此功能是为了与某些旧版系统兼容。 不建议设置为 true,因为这可能会使您的 API 遭受签名封装攻击。默认值为 false
    issuer_name_style 可选 颁发者名称的格式。有效值为 CNDN
    key_identifier_type 可选 密钥标识符类型。有效值为 BinarySecurityTokenBST_DIRECT_REFERENCEISSUER_SERIALRSA_KEY_VALUETHUMBPRINTX509_CERT_DIRECT。默认值为 BinarySecurityToken
    private_key_password 可选 密码密钥(如果私钥经过加密)。
    signing_method 可选 用于签名的相应方法。有效值为 rsa-sha1rsa-sha256。 默认为 rsa-sha1;不过,强烈建议设置为 rsa-sha256
    soap_version 可选 SOAP 版本。有效版本为 1.1 和 1.2。默认值为 1.1。
    transform_inclusive_elements 可选 用于向 Transform 元素添加 InclusiveElements 元素的命名空间 URI(而非前缀)的英文逗号分隔列表。

示例

以下示例展示了如何对 SOAP 文档进行签名。它假设私钥和证书已加载到流变量中。

var signed = crypto.wsSecRsaSign(request.content, {
    'private_key': '{private.key.pem}', // Flow variable name
    'certificate': '{public.cert.pem}', // Flow variable name
    'elements_to_sign: 
        'wsu:Timestamp, soap:Body, wsa:To, wsa:MessageID',
    'signing_method': 'rsa-sha256',
    'digest_method': 'sha256',
    expires_in': '180s'
});

使用 WS-Security 和 X.509 证书验证 SOAP 文档

使用 WS-Security 和 RSA/X.509 验证 SOAP 文档的数字签名。Gaambo 执行验证以确保传递的实参有效。

crypto.wsSecRsaValidate()

验证 SOAP 文档的数字签名。

语法

crypto.wsSecRsaValidate(payload, options)

参数

  • 载荷 - (String) 要验证的带有数字签名的 SOAP 文档。
  • options -(对象)验证的配置选项。下表列出了可用的配置选项。所有选项值都可以是字面量字符串或消息模板,使用模板字符 '{'''}' 表示。
    名称 是否必需? 说明
    accept_subject_cns 可选 主题的可接受签名者的通用名称 (CN) 的英文逗号分隔列表。 如果任何签名来自与指定 CN 不匹配的 CN,则验证失败。
    accept_thumbprints 可选 可接受的签名者的证书的 SHA-1 指纹列表(以英文逗号分隔)。 如果任何签名来自指纹与指定指纹不匹配的证书,则验证失败。 只能指定 accept-thumbprintsaccept-thumbprints-256 中的一项。如果未提供 certificate 选项,则必须提供至少一个此类选项。
    accept_thumbprints_256 可选 可接受的签名者的证书的 SHA-256 指纹列表(以英文逗号分隔)。 如果任何签名来自指纹与指定指纹不匹配的证书,则验证失败。 只能指定 accept-thumbprintsaccept-thumbprints-256 中的一项。如果未提供 certificate 选项,则必须提供至少一个此类选项。
    certificate 可选 提供用于验证签名的公钥的证书。 仅当签名文档中的 KeyInfo 未明确提供证书时,才需要使用此属性。
    digest_method 可选 支持的摘要方法。 有效值为 sha1sha256。 如果省略,则不检查摘要方法。
    ignore_certificate_expiry 可选 一个布尔值,用于指定是否忽略所提供证书上的有效日期。适用于测试。 默认值为 false
    ignore_expiry 可选 一个布尔值,用于指定在评估 SOAP 文档的有效性时是否忽略 Timestamp/Expires 字段。 默认值为 false
    ignore_security_header_placement 可选 一个布尔值,用于指定是否检查签名载荷中安全标头的位置。提供此功能是为了与某些旧版系统兼容。 不建议将此值设置为 true,因为这可能会使 API 容易受到签名封装攻击。 默认值为 false
    issuer_name_dn_comparison 可选 用于确定两个颁发者名称是否指同一实体的方法。 仅当签名文档包含封装 X509IssuerSerialKeyInfoissuer-name-styleDN(默认值)时适用。值可以是 {string, normal, reverse, unordered} 之一。默认值为 string
    issuer_name_dn_comparison_exclue_numeric_oids 可选 用于确定两个颁发者名称是否指同一实体的方法。 仅当签名文档包含封装 X509IssuerSerialKeyInfoissuer-name-styleDN(默认值),并且 issuer-name-dn-comparison 设置为 normalreverseunordered 时适用。
    issuer_name_style 可选 颁发者名称的格式。仅当签名文档包含封装 X509IssuerSerialKeyInfo 时使用。有效值包括:CNDN
    max_lifetime 可选 签名文档的最长有效期。输入 120s、10m 和 4d 等值,分别表示 120 秒、10 分钟和 4 天。此选项要求 Timestamp 包含 CreatedExpires 元素。默认情况下,没有最长使用期限。
    require_expiry 可选 一个布尔值,用于指定时间戳中是否需要包含过期时间。我们建议将此值保持设置为 true。默认值为 true
    required_sign_elements 可选 以英文逗号或空格分隔的 prefix:Tag 形式的列表,用于指明必须签名的元素。 默认值为 soap:Body, wsu:Timestamp。如需在验证时仅要求时间戳上有签名,而不要求正文上有签名,请将此属性设置为 wsu:Timestamp。如需在验证时仅要求正文上有签名,而不要求时间戳上有签名,请将此属性设置为 soap:Body。前缀和标记区分大小写。除非有特殊原因,否则我们建议您将此值保留为默认值。
    signing_method 可选 签名方法,必须与签名文档中的签名方法一致。 有效值为 rsa-sha1rsa-sha256。 如果省略,则不会检查签名方法。

示例

以下示例展示了如何验证基于 SOAP 的已签名 API。如果签名无效,系统会使用具体错误填充流变量 wssec_error

Var isValid = crypto.wsSecRsaValidate(request.content, {
        MaxLifetime: '300s',
        RequiredSignedElements: [
            '//*[local-name()=\'Body\']'
        ],
        IgnoreCertificateExpiry: false,
        TrustStore: '{truststore.pem}' // Flow variable with trusted certs
    });

 if (!isValid) {
   throw "invalid"
 }

使用 getHash() 获取任何支持的哈希对象

示例

var _hash1 = crypto.getHash('MD5');

var _hash2 = crypto.getHash('SHA-1');

var _hash3 = crypto.getHash('SHA-256');

var _hash4 = crypto.getHash('SHA-512');

加密示例

try {
    // get values to use with hash functions
    var salt = context.getVariable("salt") || 'SomeHardCodedSalt';
    var host = context.getVariable("request.header.Host");
    var unhashedToken = "";

    var _timeNow = Number(context.getVariable('system.timestamp'));
    var now = crypto.dateFormat('YYYY-MM-DD HH:mm:ss.SSS','PST', _timeNow);
    unhashed_token = "|" + now + "|" + host

    // generate a hash with the unhashedToken:
    var sha512 = crypto.getSHA512();
    sha512.update(salt);
    sha512.update(unhashedToken);

    // convert to base64
    var base64Token = sha512.digest64();

    // set headers
    context.setVariable("request.header.now", now);
    context.setVariable("request.header.token", base64Token);

} catch(e) {
    throw 'Error in Javascript';
}

上下文对象参考

系统会为 API 代理执行的每个请求/响应事务创建一个 context 对象。context 对象提供获取、设置和移除与每个事务相关的变量的方法。

变量定义了特定于事务的属性。context 中提供的变量的示例包括:一天中的时间、请求客户端的语言区域、请求客户端的用户代理、目标服务的网址。因此,context 可用于构建依赖于这些属性执行自定义行为的逻辑。

请参阅流变量参考文档ExtractVariables 政策

上下文对象摘要

下表简要介绍了上下文对象及其子对象,并列出了绑定到各个对象的属性。

名称 说明 属性
context 消息处理流水线上下文以及由 ProxyEndpoint 和 TargetEndpoint 执行的请求和响应流的封装容器。 流、会话
context.proxyRequest 表示发送到 ProxyEndpoint 的入站请求消息的对象(从请求应用到 API 代理) headers、query parameters、method、body、url
context.targetRequest 表示来自 TargetEndpoint 的出站请求消息的对象(从 API 代理到后端服务)。 headers、query parameters、method、body、url
context.targetResponse 表示入站目标响应消息的对象(从后端服务到 API 代理) headers、content、status
context.proxyResponse 表示出站代理响应消息的对象(从 API 代理到请求应用) headers、content、status
context.flow 当前流的名称。 请参阅 context.flow
context.session 名称/值对的映射,可用于在同一上下文中执行的两个不同步骤之间传递对象。例如:context.session['key'] = 123 如需详细了解何时使用以及何时不使用此对象,请参阅 context.session['hello'] = {} 与 context.setVariable("hello", {}) 之间的区别

上下文对象方法

context.getVariable()

检索预定义变量或自定义变量的值。

语法

context.getVariable("variable-name");

示例

获取当前年份的值:

var year = context.getVariable('system.time.year');

context.setVariable()

为自定义变量或任意可写预定义变量设置值。

语法

context.setVariable("variable-name", value);

示例

设置变量的常见情况是 API 代理必须动态写入目标网址。以下 JavaScript 会获取名为 USER.name 的变量的值,将该值作为查询参数附加到网址 http://mocktarget.apigee.net?user=,然后将预定义的 target.url 设置为该值。

context.setVariable("target.url", "http://mocktarget.apigee.net/user?user="+context.getVariable("USER.name"));

context.removeVariable()

从上下文中移除变量。

语法

context.removeVariable('variable-name');

上下文对象属性

context.flow

flow 属性是一个字符串,用于标识当前的 API 代理流。此属性用于表示 JavaScript 所附加到的流。支持的值为:

  • PROXY_REQ_FLOW
  • PROXY_RESP_FLOW
  • TARGET_REQ_FLOW
  • TARGET_RESP_FLOW

每个流名称都包含 PreFlow、PostFlow 以及在 ProxyEndpoint 或 TargetEndpoint 中定义的任何条件流。

如果在多个流中执行共同的 JavaScript,此可选属性会很有用,但在其执行的各个流中,其行为可能会有所不同。为要在多个 API 代理中重复使用的 JavaScript 模块使用 flow 属性;在执行逻辑之前,代码需要检查当前的 flow。

示例

仅在 targetRequest 流上设置 HTTP 标头:

if (context.flow=="TARGET_REQ_FLOW") {
     context.targetRequest.headers['TARGET-HEADER-X']='foo';
}

仅在 proxyResponse 流上设置内容:

if (context.flow=="PROXY_RESP_FLOW") {
     context.proxyResponse.content='bar';
}

context.session

名称/值对的映射,可用于在同一消息上下文中执行的两个政策之间传递对象。

示例

在会话中设置值:

context.session['key']  = 123;

获取会话中的值:

var value = context.session['key']; // 123

上下文对象的子对象

如下所示,一个完整的 API 代理流包括四个不同的阶段,每个阶段都有一个关联的消息对象,该对象是上下文对象的子对象:

  • context.proxyRequest:从请求客户端收到的入站请求消息。
  • context.targetRequest:发送到后端服务的出站请求消息。
  • context.proxyResponse:返回到请求客户端的出站响应消息。
  • context.targetResponse:从后端服务收到的入站请求消息。

通过代理端点和目标端点的请求和响应的示意图。

以下各部分介绍这些对象的方法和属性:

context.*请求子对象

对于在 API 代理中执行每个的 HTTP 事务,系统会创建两个请求消息对象:一个“入站”(来自客户端的请求)和一个“出站”(由 API 代理生成并提交给后端目标的请求)。

context 对象具有表示这些请求消息的子对象:context.proxyRequestcontext.targetRequest。通过这些对象,您可以访问 JavaScript 代码执行范围内的请求流内的属性。

context.*请求子对象属性

属性名称 说明
url

url 是一个方便读写的属性,包含 targetRequest 的架构、主机、端口、路径和查询参数。

请求的完整网址由以下属性组成:

  • protocol:网址的协议(例如 HTTP、HTTPS)
  • port:端口(例如 :80、:443)
  • host:网址的主机(例如 www.example.com)
  • path:URI 的路径(例如 /v1/mocktarget)

获取 url 时,网址会按以下格式返回:

protocol://host:port/path?queryParams

示例:

context.targetRequest.url = 'http://www.example.com/path?q1=1'
context.targetRequest.protocol ='https';
headers

形式为 String => List 映射的 HTTP 请求标头

示例:

对于此 HTTP 请求:

POST /v1/blogs HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer ylSkZIjbdWybfs4fUQe9BqP0LH5Z
以下 JavaScript:
context.proxyRequest.headers['Content-Type'];
context.proxyRequest.headers['Authorization'];

将返回以下值

application/json
Bearer ylSkZIjbdWybfs4fUQe9BqP0LH5Z
queryParams

形式为 String => List 映射的请求消息查询参数。

示例:

"?city=PaloAlto&city=NewYork"

可以访问如下:

context.proxyRequest.queryParams['city'];  // == 'PaloAlto'
context.proxyRequest.queryParams['city'][0]     // == 'PaloAlto'
context.proxyRequest.queryParams['city'][1];    // == 'NewYork'
context.proxyRequest.queryParams['city'].length(); // == 2
method

与请求关联的 HTTP 动词(GET、POST、PUT、DELETE、PATCH 等)

示例:

对于此请求:

POST /v1/blogs HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer ylSkZIjbdWybfs4fUQe9BqP0LH5Z

以下 JavaScript:

context.proxyRequest.method;

将返回以下值

POST
body

HTTP 请求的消息正文(载荷)。

请求正文具有以下成员:

  • context.targetRequest.body.asXML;
  • context.targetRequest.body.asJSON;
  • context.targetRequest.body.asForm;

示例:

对于 XML 正文:

<customer number='1'>
<name>Fred<name/>
<customer/>

按如下所示访问 XML 对象的元素:

var name = context.targetRequest.body.asXML.name;

要访问 XML 属性,请使用 @ 表示法。

var number = context.targetRequest.body.asXML.@number;

对于 JSON 请求正文:

{
"a":  1 ,
"b" : "2"
}
var a = context.proxyRequest.body.asJSON.a;    // == 1
var b = context.proxyRequest.body.asJSON.b;    // == 2

按如下所示读取表单参数:

"vehicle=Car&vehicle=Truck"
v0 = context.proxyRequest.body.asForm['vehicle'][0];
v1 = context.proxyRequest.body.asForm['vehicle'][1];

context.*响应子对象

对于在 API 代理中执行的每个 HTTP 事务,系统会创建两个响应消息对象:一个“入站”(后端服务的响应)和一个“出站”(将发送回客户端的响应)。

上下文对象具有代表这些响应消息的子对象:context.proxyResponsecontext.targetResponse。通过这些对象,您可以访问 JavaScript 代码执行范围内的响应流内的属性。

context.*响应对象属性

属性名称 说明
headers

形式为 String => List 映射的响应消息的 HTTP 标头。

示例:

var cookie = context.targetResponse.headers['Set-Cookie'];
status

作为属性的状态代码,带有状态消息。状态代码和状态消息均作为属性提供。

示例:

var status = context.targetResponse.status.code;   // 200
var msg = context.targetResponse.status.message;   // "OK"
content

响应消息的 HTTP 正文(载荷内容)。

响应内容包括以下成员:

context.targetResponse.content.asXML;
context.targetResponse.content.asJSON;

使用 .asXML 表示法

使用 .asXML 表示法可以方便地浏览 XML 文档。本部分介绍如何使用此表示法,以及它与 request.contentcontext.proxyRequest.content 之间的区别。

例如:

request.content.asXML

context.proxyRequest.content.asXML

*.content*.content.asXML 形式在字符串上下文中都可以使用,JavaScript 会将其强制转换为字符串。在前一种情况 (*.content) 中,字符串包括所有声明以及 XML 注释。在后一种情况 (*.content.asXML) 中,结果的字符串值会清除声明和注释。

示例

msg.content:

<?xml version="1.0" encoding="UTF-8"?>
<yahoo:error xmlns:yahoo="http://yahooapis.com/v1/base.rng" xml:lang="en-US">
   <yahoo:description>Please provide valid credentials. OAuth oauth_problem="unable_to_determine_oauth_type", realm="yahooapis.com"
   </yahoo:description>
</yahoo:error>
<!-- mg023.mail.gq1.yahoo.com uncompressed/chunked Sat Dec 14 01:23:35 UTC 2013 -->

msg.content.asXML:

<?xml version="1.0" encoding="UTF-8"?>
<yahoo:error xmlns:yahoo="http://yahooapis.com/v1/base.rng" xml:lang="en-US">
   <yahoo:description>Please provide valid credentials. OAuth oauth_problem="unable_to_determine_oauth_type", realm="yahooapis.com"
   </yahoo:description>
</yahoo:error>

此外,您还可以使用 .asXML 形式通过指定元素和属性的名称来遍历 XML 层次结构。您无法使用其他语法遍历层次结构。

使用 JavaScript print() 语句进行调试

请注意,如果您使用 JavaScript 政策执行自定义 JavaScript 代码,则可以使用 print() 函数将调试信息输出到调试工具。此函数可直接通过 JavaScript 对象模型提供。例如:

if (context.flow=="PROXY_REQ_FLOW") {
     print("In proxy request flow");
     var username = context.getVariable("request.queryparam.user");
     print("Got query param: " + username);
     context.setVariable("USER.name", username);
     print("Set query param: " + context.getVariable("USER.name"));
}


if (context.flow=="TARGET_REQ_FLOW") {
     print("In target request flow");
     var username = context.getVariable("USER.name");
     var url = "http://mocktarget.apigee.net/user?"
     context.setVariable("target.url", url + "user=" + username);
     print("Callout to URL: ", context.getVariable("target.url"));
}

要查看输出,请选择调试窗口底部的从所有事务输出 (Output from all transactions)。您还可以在名为 stepExecution-stdout 的调试属性中找到输出。

使用 httpClient 进行 JavaScript 调出

使用 httpClient 从在 API 代理流中执行的自定义 JavaScript 代码内向任意网址发送多个并行的异步 HTTP 请求。httpClient 对象由 Apigee JavaScript 对象模型公开。

httpClient 简介

httpClient 对象通过 JavaScript 对象模型,对在 Apigee 上运行的自定义 JavaScript 代码公开。要将自定义 JavaScript 附加到 API 代理,请使用 JavaScript 政策。当该政策运行时,自定义 JavaScript 代码会执行。

httpClient 对象可用于开发复合服务或混搭。例如,您可以将多个后端调用合并为一个 API 方法。

以下是基本用法。实例化一个请求对象,为其分配一个网址(例如,您要调用的后端服务),并使用该请求对象调用 httpClient.send

var myRequest = new Request();
myRequest.url = "http://www.example.com";
var exchangeObj = httpClient.send(myRequest);

httpClient 参考

HTTP 客户端提供两种方法:get()send()

httpClient.get()

用于简单的 HTTP GET 请求的便捷方法,不支持 HTTP 标头。

用量

var exchangeObj = httpClient.get(url);

返回结果

该方法会返回一个 exchange 对象。此对象没有属性,并提供以下方法:

  • isError():(布尔值)如果 httpClient 无法连接到服务器,则返回 true。当连接完成并且返回有效的响应代码,HTTP 状态代码 4xx5xx 会导致 isError() false。如果 isError() 返回 true,则对 getResponse() 的调用会返回 JavaScript undefined
  • isSuccess():(布尔值)如果发送完成且成功,则返回 true
  • isComplete():(布尔值)如果请求完成,则返回 true
  • waitForComplete():暂停线程,直到请求完成(成功或错误)。
  • getResponse():(对象)如果 httpClient.send() 完成并成功,则返回响应对象。返回的对象具有与 context.proxyResponse 对象相同的方法和属性。请参阅上下文对象摘要
  • getError():(字符串)如果对 httpClient.send() 的调用导致错误,则以字符串形式返回错误消息。

示例

发送包含 HTTP 请求属性的完全配置的请求对象。使用非阻塞回调来处理响应。

// Add the required the headers for making a specific API request
var headers = {'X-SOME-HEADER' : 'some value' };
// Make a GET API request along with headers
var myRequest = new Request("http://www.example.com","GET",headers);

// Define the callback function and process the response from the GET API request
function onComplete(response,error) {
 // Check if the HTTP request was successful
    if (response) {
      context.setVariable('example.status', response.status);
     } else {
      context.setVariable('example.error', 'Woops: ' + error);
     }
}

// Specify the callback Function as an argument
httpClient.get(myRequest, onComplete);

使用 JavaScript 政策

使用 JavaScript 政策将自定义 JavaScript 代码附加到代理流。 请参阅 JavaScript 政策

相关主题