JavaScript 物件模型

您正在查看 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允許存取要求物件的簡寫
  • 回應允許存取要求物件的簡寫
  • crypto提供各種雜湊函式。
  • print發出輸出的函式
  • properties允許讀取政策設定屬性的權限

情境物件

context 物件具有全域範圍。您可以在 API Proxy 流程中的任何位置使用這項工具。有四個子項物件:proxyRequestproxyResponsetargetRequesttargetResponse。這些子項物件的範圍限定在環境要求和回應 (Proxy 要求和回應,或是目標要求和回應)。舉例來說,如果 JavaScript 政策在流程的 Proxy 端點部分執行,那麼 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 要求流程中,這會設為常數 PROXY_REQ_FLOW。如果是在目標回應流程中,則會設為 TARGET_RESP_FLOW。執行範圍專用程式碼時,這個常數就非常實用。getter 可讓您取得流程變數,而 setter 則可讓您設定流程變數。這些變數通常在 Proxy 流程中開放使用,可供其他政策使用。

如需詳細資訊和範例,請參閱下方的內容物件參考資料

加密物件

加密編譯物件可為 JavaScript 物件模型新增基本的高效能加密編譯支援。如需詳細資訊和範例,請參閱下方的加密物件參考資料

要求和回應物件

requestresponse 物件是微光要求和回應的「簡短」參照:Proxy 要求和回應,或目標要求和回應。這些變數參照的物件取決於執行 JavaScript 政策的結構定義。如果 JavaScript 在 Proxy 端點流程中執行,則要求和回應變數會參照 context.proxyRequestcontext.proxyResponse。如果 JavaScript 在目標流程中執行,則變數會參照 context.targetRequestcontext.targetResponse

JavaScript 物件模型包含 print() 函式,可用來將偵錯資訊輸出至 Edge Trace 工具。請參閱「使用 JavaScript print() 陳述式進行偵錯」。

屬性物件

在政策設定中使用 元素時,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 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 物件並加以更新,並將其轉換為 16 進位值和 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();

將 MD5 物件以 Base64 字串傳回

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');

立即取得十秒的值:

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 代表 Proxy 端點 (從提出要求的應用程式到 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');

情境物件屬性

context.flow

flow 屬性是識別目前 API Proxy 流程的字串。這個屬性用來指出附加 JavaScript 的流程。支援的值如下:

  • PROXY_REQ_FLOW
  • PROXY_RESP_FLOW
  • TARGET_REQ_FLOW
  • TARGET_RESP_FLOW

每個流程名稱都包含 PreFlow、PostFlow,以及在 Proxy Endpoints 或目標端點中定義的任何條件式流程。

如果您在多個流程中執行常見的 JavaScript,這項選用屬性可能非常實用,但其行為可能會因執行流程而不同。針對要在多個 API Proxy 中重複使用的 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 Proxy 流程包含四個不同的階段,每個階段都具有相關聯的訊息物件,該階段是結構定義物件的子項:

  • context.proxyRequest:從要求用戶端收到的傳入要求訊息。
  • context.targetRequest:傳送至後端服務的傳出要求訊息。
  • context.proxyResponse:傳回給要求用戶端的傳出回應訊息。
  • context.targetResponse:從後端服務收到的傳入要求訊息。

以下各節說明這些物件的方法和屬性:

context。*要求子物件

針對在 API Proxy 中執行的每項 HTTP 交易,系統會建立兩個要求訊息物件:一個「傳入」inbound (來自用戶端的要求),以及一個「傳出」inbound (由 API Proxy 產生並提交至後端目標的要求)。

context 物件包含代表這些要求訊息的子項物件:context.proxyRequestcontext.targetRequest。這些物件可讓您在執行 JavaScript 程式碼時,存取要求流程範圍內的屬性。

注意:您也可以使用 shorthand 物件 request 在要求流程中存取這些屬性。request 物件會根據 JavaScript 程式碼執行流程中的位置,參照 context.proxyRequestcontext.targetRequest

content.*要求子物件屬性

資源名稱 說明
url

url 屬性是可讀取/寫入的便利屬性,可結合 targetRequest 的配置、主機、通訊埠、路徑和查詢參數。

要求的完整網址是由下列屬性組成:

  • 通訊協定:網址的通訊協定 (例如 HTTP、HTTPS)
  • 通訊埠:通訊埠 (例如 :80, :443)
  • 主機:網址主機 (例如 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

HTTP 要求標頭做為 String => List 的對應

例:

針對此 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 動詞 (GETPOSTPUTDELETEPATCH 等)

例:

針對這個要求:

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 Proxy 中執行的每項 HTTP 交易,系統會建立兩個回應訊息物件:一個「傳入」inbound (後端服務的回應) 和一個「傳出」inbound (回應傳回用戶端的回應)。

結構定義物件包含代表這些回應訊息的子項物件:context.proxyResponsecontext.targetResponse。這些物件可讓您在執行 JavaScript 程式碼時,存取回應流程範圍內的屬性。

注意:您也可以使用 shorthand 物件 response,從回應流程存取這些屬性。response 物件會根據 JavaScript 程式碼執行流程中的位置,參照 context.proxyResponsecontext.targetResponse

content.*回應物件屬性

資源名稱 說明
headers

回應訊息的 HTTP 標頭,做為 String => List 的對應。

示例:

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() 函式將偵錯資訊輸出至「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」。您也可以在名為 stepExecution-stdout 的 Trace 屬性中找到輸出內容。

使用 httpClient 進行 JavaScript 呼叫

使用 httpClient 即可從 API Proxy 流程中執行的自訂 JavaScript 程式碼內,對任何網址發出多個平行的非同步 HTTP 要求。httpClient 物件是由 Apigee Edge JavaScript 物件模型公開,

關於 httpClient

httpClient 物件會透過 JavaScript 物件模型,向在 Apigee Edge 上執行的自訂 JavaScript 程式碼公開,如要將自訂 JavaScript 附加至 API Proxy,請使用 JavaScript 政策。當政策執行時,系統就會執行自訂 JavaScript 程式碼。

httpClient 物件適合用於開發複合服務或混搭。舉例來說,您可以將多個後端呼叫合併為單一 API 方法。 這個物件通常會做為 Service Call 政策的替代方案。

基本的使用模式如下:對要求物件執行個體化、指派給網址 (例如您要呼叫的後端服務),然後使用該要求物件呼叫 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 要求屬性的完整設定 Request 物件。使用非阻塞的回呼來處理回應。

// 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 政策

相關主題

Apigee 社群文章

您可以前往 Apigee 社群找到下列相關文章: