本頁適用於 Apigee 和 Apigee Hybrid。
查看
Apigee Edge 說明文件。
本主題將說明 Apigee JavaScript 物件模型。如果您打算使用 JavaScript 政策,在 API 代理程式中加入自訂 JavaScript,就必須瞭解這個模型。
關於 JavaScript 物件模型
JavaScript 物件模型會定義物件及其相關聯的屬性,這些屬性可供在 Apigee 代理程式流程中執行的 JavaScript 程式碼使用。使用 JavaScript 政策將這段自訂程式碼附加至 API Proxy 流程。
這個模型定義的物件在 API Proxy 流程中具有範圍,也就是說,特定物件和屬性僅在流程中的特定位置可用。執行 JavaScript 時,系統會為執行作業建立範圍。在該範圍內,系統會建立下列物件參照:
- context:提供訊息內容存取權的物件
- request:可存取要求物件的簡寫字詞
- response:可存取回應物件的簡寫字詞
- crypto:提供各種雜湊函式
- print:用於輸出內容的函式
- properties:允許對政策中的設定屬性具備讀取權限
背景資訊物件
context
物件具有全域範圍。可在 API Proxy 流程中的任何位置使用。它有四個子物件:proxyRequest
、proxyResponse
、targetRequest
、targetResponse
。這些子物件的範圍為環境要求和回應,也就是 Proxy 要求和回應,或是目標要求和回應。舉例來說,如果 JavaScript 政策是在流程的 Proxy 端點部分執行,那麼 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 要求流程中,此值會設為常數 PROXY_REQ_FLOW
。如果在目標回應流程中,則會設為 TARGET_RESP_FLOW
。這個常數可用於執行特定範圍的程式碼。getter 可讓您取得流量變數,setter 則可讓您設定流量變數。這些變數通常會在 Proxy 流程中提供,且可供其他政策使用。
詳情請參閱內容物件參照,瞭解更多資訊和示例。
加密物件
加密物件可為 JavaScript 物件模型新增基本且高效能的加密支援功能。詳情請參閱加密物件參考資料。
要求和回應物件
request
和 response
物件是簡寫參照環境要求和回應的物件,可能是 Proxy 要求和回應,也可能是目標要求和回應。這些變數參照的物件取決於 JavaScript 政策執行的內容。如果 JavaScript 在代理端點的流程中執行,則要求和回應變數會參照 context.proxyRequest
和 context.proxyResponse
。如果 JavaScript 在目標流程中執行,則變數會參照 context.targetRequest
和 context.targetResponse
。
print() 函式
JavaScript 物件模型包含 print() 函式,可用於將偵錯資訊輸出至 Apigee Debug 工具。請參閱「使用 JavaScript print() 陳述式進行偵錯」。
屬性物件
在政策設定中使用 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)); }
加密物件參考
您可以使用 crypto 物件在 JavaScript 中執行基本的加密編譯雜湊函式。
crypto 物件具有全域範圍。可在 API Proxy 流程中的任何位置使用。Crypto 可讓您使用下列雜湊物件:
- SHA-1
- SHA256
- SHA512
- MD5
使用 SHA-1 物件
您可以建立 SHA-1 物件、更新物件,並將物件轉換為十六進位和 base64 值。
建立新的 SHA-1 物件
var _sha1 = crypto.getSHA1();
更新 SHA-1 物件
語法
_sha1.update(value);
Parameters
- 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);
Parameters
- 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);
Parameters
- 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);
Parameters
- 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])
Parameters
- format - (字串) 此參數的基礎實作為 java.text.SimpleDateFormat。例如:'YYYY-MM-DD HH:mm:ss.SSS'
- timezone - (字串,選用) 此參數的基礎實作項目為 java.util.TimeZone。此參數與預設值相同:世界標準時間
- 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 Proxy 執行的每個要求/回應交易建立 context
物件。context
物件會公開方法,用於取得、設定及移除與每筆交易相關的變數。
變數會定義交易專屬的屬性。context
中可用的變數範例包括:時間、要求用戶端的語言代碼、要求用戶端的使用者代理程式,以及目標服務的網址。因此,context
可用於建構依賴這些屬性執行自訂行為的邏輯。
請參閱「流程變數參考資料」和「ExtractVariables 政策」。
context 物件摘要
下表簡要說明內容物件及其子項,並列出繫結至每個內容物件的屬性。
名稱 | 說明 | 屬性 |
---|---|---|
context |
訊息處理管道內容的包裝函式,以及由 ProxyEndpoint 和 TargetEndpoint 執行的要求和回應流程。 | flow、session |
context. proxyRequest |
代表 ProxyEndpoint 中傳入要求訊息的物件 (從要求應用程式傳送至 API Proxy) | 標頭、查詢參數、方法、內文、網址 |
context. targetRequest |
代表來自 TargetEndpoint 的外寄要求訊息 (從 API Proxy 傳送至後端服務) 的物件。 | 標頭、查詢參數、方法、內容、網址 |
context. targetResponse |
代表內送目標回應訊息的物件 (從後端服務傳送至 API Proxy) | 標頭、內容和狀態 |
context. proxyResponse |
代表外寄 Proxy 回應訊息的物件 (從 API Proxy 傳送至要求應用程式) | 標頭、內容和狀態 |
context.flow |
目前流程的名稱。 | 請參閱 context.flow。 |
context.session |
名稱/值組合的對應,可用於在同一個情境中執行的兩個不同步驟之間傳遞物件。例如 context.session['key'] = 123 。 |
如要進一步瞭解何時應使用或不使用這個物件,請參閱「context.session['hello'] = {} 與 context.setVariable("hello", {}) 有何不同?」。 |
context 物件方法
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
每個流程名稱都包含 ProxyEndpoint 或 TargetEndpoint 中定義的 PreFlow、PostFlow 和任何條件式流程。
當常見的 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
context object 子項
如以下所示,完整的 API 代理程式流程包含四個不同的階段,每個階段都有一個關聯的訊息物件,該物件是內容物件的子項:
context.proxyRequest
:從要求用戶端收到的內送要求訊息。context.targetRequest
:傳送至後端服務的傳出要求訊息。context.proxyResponse
:傳回給要求用戶端的傳出回應訊息。context.targetResponse
:從後端服務收到的入站要求訊息。
以下各節將說明這些物件的方法和屬性:
context.*Request 子物件
對於在 API Proxy 中執行的每個 HTTP 交易,系統會建立兩個要求訊息物件:一個「inbound」 (來自用戶端的要求) 和一個「outbound」 (由 API Proxy 產生並提交至後端目標的要求)。
context
物件包含代表這些要求訊息的子物件:context.proxyRequest
和 context.targetRequest
。這些物件可讓您在執行 JavaScript 程式碼時,存取要求流程中的屬性。
context.*Request 子項物件屬性
屬性名稱 | 說明 |
---|---|
url |
要求的完整網址由下列屬性組成:
取得
|
範例: context.targetRequest.url = 'http://www.example.com/path?q1=1' context.targetRequest.protocol ='https'; |
|
headers |
HTTP 要求標頭做為 |
範例: 針對此 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 要求的訊息主體 (payload)。 要求主體包含下列成員:
|
範例: 針對 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.*Response 子項物件
對於在 API Proxy 中執行的每個 HTTP 交易,系統都會建立兩個回應訊息物件:一個傳入 (來自後端服務的回應) 和一個傳出 (傳回給用戶端的回應)。
內容物件包含代表這些回應訊息的子物件:context.proxyResponse
和 context.targetResponse
。這些物件可讓您在執行 JavaScript 程式碼時,存取回應流程中的屬性。
context.*Response 物件屬性
屬性名稱 | 說明 |
---|---|
headers |
回應訊息的 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.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")); }
如要查看輸出內容,請選取「Debug」視窗底部的「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()
的呼叫導致錯誤,則會以字串形式傳回錯誤訊息。
示例
傳送已完整設定的 Request 物件,其中包含 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 程式碼附加至 Proxy 流程。 請參閱 JavaScript 政策。