本页面适用于 Apigee 和 Apigee Hybrid。
查看 Apigee Edge 文档。
本主题讨论了 Apigee JavaScript 对象模型。如果您打算使用 JavaScript 政策将自定义 JavaScript 添加到 API 代理,则必须了解此模型。
JavaScript 对象模型简介
JavaScript 对象模型定义具有关联属性的对象,这些对象可供在 Apigee 代理流中执行的 JavaScript 代码使用。可以使用 JavaScript 政策将此自定义代码附加到 API 代理流。
此模型定义的对象的范围在 API 代理流内,这意味着某些对象和属性仅在流程的特定点可用。当 JavaScript 执行时,系统会为执行创建一个范围。在该范围内创建以下对象引用:
- context:提供消息上下文访问权限的对象
- request:允许访问请求对象的简便方法
- response:允许访问响应对象的简写
- crypto:提供各种哈希函数
- print:用于发出输出的函数
- properties:允许读取政策中的配置属性
上下文对象
context
对象具有全局范围。它在 API 代理流中的任何位置都可用。它有四个子对象:proxyRequest
、proxyResponse
、targetRequest
、targetResponse
。这些子对象仅限于环境请求和响应,包括代理请求和响应以及目标请求和响应。例如,如果 JavaScript 政策在流的代理端点部分执行,则 context.proxyRequest
和 context.proxyResponse
对象都在范围内。如果 JavaScript 在目标流中运行,则 context.targetRequest
和 context.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 对象
request
和 response
对象是环境请求和响应的“简写”,可以是代理请求和响应,也可以是目标请求和响应。这些变量引用的对象取决于执行 JavaScript 政策的上下文。如果 JavaScript 在代理端点流中运行,则请求和响应变量引用的是 context.proxyRequest
和 context.proxyResponse
。如果 JavaScript 在目标流中运行,则变量引用的是 context.targetRequest
和 context.targetResponse
。
print() 函数
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");
使用 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');
上下文对象属性
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['key'] = 123;
获取会话中的值:
var value = context.session['key']; // 123
上下文对象的子对象
如下所示,一个完整的 API 代理流包括四个不同的阶段,每个阶段都有一个关联的消息对象,该对象是上下文对象的子对象:
context.proxyRequest
:从请求客户端收到的入站请求消息。context.targetRequest
:发送到后端服务的出站请求消息。context.proxyResponse
:返回到请求客户端的出站响应消息。context.targetResponse
:从后端服务收到的入站请求消息。
以下各部分介绍这些对象的方法和属性:
context.*请求子对象
对于在 API 代理中执行每个的 HTTP 事务,系统会创建两个请求消息对象:一个“入站”(来自客户端的请求)和一个“出站”(由 API 代理生成并提交给后端目标的请求)。
context
对象具有表示这些请求消息的子对象:context.proxyRequest
和 context.targetRequest
。通过这些对象,您可以访问 JavaScript 代码执行范围内的请求流内的属性。
context.*请求子对象属性
属性名称 | 说明 |
---|---|
url |
请求的完整网址由以下属性组成:
获取
|
示例: context.targetRequest.url = 'http://www.example.com/path?q1=1' context.targetRequest.protocol ='https'; |
|
headers |
形式为 |
示例: 对于此 HTTP 请求: POST /v1/blogs HTTP/1.1 Host: api.example.com Content-Type: application/json Authorization: Bearer ylSkZIjbdWybfs4fUQe9BqP0LH5Z context.proxyRequest.headers['Content-Type']; context.proxyRequest.headers['Authorization']; 将返回以下值 application/json Bearer ylSkZIjbdWybfs4fUQe9BqP0LH5Z |
|
queryParams |
形式为 |
示例: "?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 请求的消息正文(载荷)。 请求正文具有以下成员:
|
示例: 对于 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.proxyResponse
和 context.targetResponse
。通过这些对象,您可以访问 JavaScript 代码执行范围内的响应流内的属性。
context.*响应对象属性
属性名称 | 说明 |
---|---|
headers |
形式为 |
示例: 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.content
和 context.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 状态代码4xx
和5xx
会导致isError()
false
。如果isError()
返回true
,则对getResponse()
的调用会返回 JavaScriptundefined
。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 政策。