您正在查看 Apigee Edge 說明文件。
查看 Apigee X 說明文件。
本主題討論 Apigee Edge JavaScript 物件模型。如果您打算使用 JavaScript 政策在 API Proxy 中新增自訂 JavaScript,就必須瞭解這個模型。
關於 Edge JavaScript 物件模型
Apigee Edge JavaScript 物件模型會定義相關屬性,而這些屬性可在 Apigee Edge Proxy 流程中執行的 JavaScript 程式碼使用。請使用 JavaScript 政策,將這個自訂程式碼附加至 API Proxy 流程。
這個模型定義的物件在 API Proxy 流程中具有「範圍」,這表示某些物件和屬性只能在流程的特定時間點使用。JavaScript 執行時,系統會為執行作業建立範圍。在該範圍內,系統會建立這些物件參照:
- context:提供訊息結構定義存取權的物件
- request:允許存取要求物件的短片
- response:允許存取要求物件的簡短程式碼
- 加密編譯:提供各種雜湊函式
- print:用於輸出輸出的函式
- property:授予政策設定的屬性讀取權限
結構定義物件
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 在 Proxy 端點的流程中執行,則要求和回應變數指的是 context.proxyRequest
和 context.proxyResponse
。如果 JavaScript 在目標流程中執行,變數就會參照 context.targetRequest
和 context.targetResponse
。
print() 函式
JavaScript 物件模型包含 print()
函式,可用來將偵錯資訊輸出至 Edge Trace 工具。請參閱「使用 JavaScript Print() 陳述式進行偵錯」。
屬性物件
在政策設定中使用 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 Proxy 流程中的任何位置使用。Crypto 可讓您處理下列雜湊物件:
- SHA-1
- SHA256
- SHA512
- MD5
使用 SHA-1 物件
您可以建立 SHA-1 物件、更新物件,並將其轉換為十六進位和 Base64 值。
建立新的 SHA-1 物件
var _sha1 = crypto.getSHA1();
更新 SHA-1 物件
語法
_sha1.update(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);
參數
- 值 - (字串) 任何字串值。
範例
更新 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);
參數
- 值 - (字串) 任何字串值。
範例
更新 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);
參數
- 值 - (字串) 任何字串值。
範例
更新 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
- 時間 - (數字,選填) 要格式化的 Unix 時間戳記值。預設:目前時間
範例
取得目前時間 (單位為毫秒):
var _now = crypto.dateFormat('yyyy-MM-DD HH:mm:ss.SSS');
取得太平洋時間的時區:
var _pst = crypto.dateFormat('yyyy-MM-DD HH:mm:ss.SSS','PST');
立即取得十秒的值:
var _timeNow = Number(context.getVariable('system.timestamp')); var ten_seconds = 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 unhashed_token = ""; 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(unhashed_token); //convert to base64 var base64_token = sha512.digest64(); // set headers context.setVariable("request.header.now", now); context.setVariable("request.header.token", base64_token); } catch(e) { throw 'Error in Javascript'; }
結構定義物件參考資料
系統會針對 API Proxy 執行的每個要求/回應交易建立 context
物件。context
物件會公開用於取得、設定及移除與每筆交易相關的變數。
變數定義了交易專屬的屬性。時段、要求用戶端的語言代碼、要求用戶端的使用者代理程式,以及目標服務的網址都是 context
中提供的變數。因此,context
可用於建構使用這些屬性的邏輯以執行自訂行為。
結構定義物件摘要
下表簡要說明結構定義物件及其子項,並列出繫結至每個物件的屬性。
名稱 | 說明 | 屬性 |
---|---|---|
context |
訊息處理管道結構定義,以及 ProxyEndpoint 和 TargetEndpoint 執行的要求與回應流程。 | 流程、工作階段 |
context. proxyRequest |
代表對 ProxyEndpoint (來自要求應用程式至 API Proxy) 的傳入要求訊息的物件 | 標頭、查詢參數、方法、內文、網址 |
context. targetRequest |
代表目標端點 (從 API Proxy 到後端服務) 的傳出要求訊息。 | 標頭、查詢參數、方法、內文、網址 |
context. targetResponse |
代表傳入目標回應回應的物件 (從後端服務到 API Proxy) | 標頭、內容、狀態 |
context. proxyResponse |
代表外送 Proxy 回應訊息 (從 API Proxy 到提出要求的應用程式) 的物件 | 標頭、內容、狀態 |
context.flow |
目前流程的名稱。 | 請參閱下方的 context.flow。 |
context.session |
名稱/值組合的對應,可在相同內容中執行的兩個不同步驟之間傳遞物件。例如 context.session['key'] = 123 。 |
如要進一步瞭解不使用該物件的時機和時機,請參閱這篇 Apigee 社群討論。 |
結構定義物件方法
context.getVariable()
擷取預先定義的變數或自訂變數的值。
語法
context.getVariable("variable-name");
範例
如要取得當年度的值,請按照下列步驟操作:
var year = context.getVariable('system.time.year');
context.setVariable()
設定自訂變數或任何可寫入的 變數的值。
語法
context.setVariable("variable-name", value);
範例
設定變數的常見情況是 API Proxy 必須動態寫入目標網址。以下 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 Proxy 流程的字串。這個屬性是用來指出附加 JavaScript 的流程。支援的值如下:
PROXY_REQ_FLOW
PROXY_RESP_FLOW
TARGET_REQ_FLOW
TARGET_RESP_FLOW
每個流程名稱都包含 PreFlow、PostFlow,以及 ProxyEndpoint 或 TargetEndpoint 中定義的任何條件式流程。
當通用 JavaScript 在多個流程中執行時,這個選用屬性會很有用,但可能會針對不同執行流程的執行行為有所不同。請在 JavaScript 模組中使用 Flow 屬性,以便在多個 API Proxy 中重複使用。您必須在執行邏輯前檢查程式碼,才能檢查目前的 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 Proxy 流程包含四個不同的階段,每個階段都有相關聯的訊息物件,做為結構定義物件的子項:
context.proxyRequest
:從要求用戶端收到的傳入要求訊息。context.targetRequest
:傳送至後端服務的傳出要求訊息。context.proxyResponse
:傳回要求用戶端的傳出回應訊息。context.targetResponse
:來自後端服務的傳入要求訊息。
以下各節說明這些物件的方法和正確性:
Context.*要求子項物件
針對在 API Proxy 中執行的每項 HTTP 交易,系統會建立兩個要求訊息物件:一個「繫結」 (從用戶端傳出的要求) 和「傳出」 (由 API Proxy 產生並提交至後端目標的要求)。
context
物件中的子物件代表這些要求訊息:context.proxyRequest
和 context.targetRequest
。這些物件可讓您在 JavaScript 程式碼執行時,在要求流程中存取屬性。
注意:您也可以使用捷徑物件 request
在要求流程中存取這些屬性。request
物件是指 context.proxyRequest
或 context.targetRequest
,視 JavaScript 程式碼的執行位置而定。
rel.*要求子項物件屬性
資源名稱 | 說明 |
---|---|
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以下 JavaScript: 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 動詞 ( |
示例: 針對這項要求: 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.*Response 子物件
每次在 API Proxy 中執行的 HTTP 交易都會建立兩個回應訊息物件,一個「繫結」 (來自後端服務的回應) 和一個「傳出」 (將回應傳回至用戶端)。
結構定義物件含有代表這些回應訊息的子項物件:context.proxyResponse
和 context.targetResponse
。這些物件可讓您在 JavaScript 程式碼執行時,在回應流程中存取屬性。
注意:您也可以使用簡易物件 response
從回應流程存取這些屬性。response
物件是指 context.proxyResponse
或 context.targetResponse
,視 JavaScript 程式碼的執行位置而定。
rel.*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() 函式將偵錯資訊輸出至 Trace 工具。您可以直接透過 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")); }
如要查看輸出內容,請選取「Trace」視窗底部的「Output from all transaction」(所有交易的輸出內容)。您也可以在 Trace 屬性中找到 stepExecution-stdout
的輸出內容。
使用 httpClient 執行 JavaScript 呼叫
您可以使用 httpClient
,針對在 API Proxy 流程中執行的自訂 JavaScript 程式碼,向多個網址發出多個非同步 HTTP 要求。
httpClient
物件是由 Apigee Edge JavaScript 物件模型公開。
關於 httpClient
httpClient
物件會透過 JavaScript 物件模型在 Apigee Edge 上執行的自訂 JavaScript 程式碼。如要將自訂 JavaScript 附加至 API Proxy,請使用 JavaScript 政策。政策執行時,系統會執行自訂 JavaScript 程式碼。
httpClient
物件適合用於開發複合服務或混搭。例如,您可以將多個後端呼叫合併為單一 API 方法。這個物件常用於 ServiceSummary 政策的替代方案。
以下是基本使用模式。對 Request 物件執行個體化,並將其指派給網址 (例如您要呼叫的後端服務),然後使用該要求物件呼叫 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()
已完成且成功,會傳回回應物件。傳回的物件採用的情境和屬性與 rel.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 程式碼附加至 Proxy 流程。請參閱 JavaScript 政策。
相關主題
- JavaScript 政策
- JavaScript 物件模型
- 如需基本範例和操作說明,請參閱使用 JavaScript 編寫 API Proxy。
- 如需有效的 JavaScript 程式碼範例,請參閱 GitHub 上的 Apigee Edge 範例。
Apigee 社群文章
如要查看這些相關文章,請前往 Apigee 社群: