

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# API Gateway 中的 Lambda 代理整合
<a name="set-up-lambda-proxy-integrations"></a>

下一節顯示如何使用 Lambda 代理整合。

**Topics**
+ [了解 API Gateway Lambda 代理整合](#api-gateway-create-api-as-simple-proxy)
+ [支援多值標頭和查詢字串參數](#apigateway-multivalue-headers-and-parameters)
+ [代理整合之 Lambda 函數的輸入格式](#api-gateway-simple-proxy-for-lambda-input-format)
+ [代理整合之 Lambda 函數的輸出格式](#api-gateway-simple-proxy-for-lambda-output-format)
+ [使用 設定 API Gateway 的 Lambda 代理整合 AWS CLI](set-up-lambda-proxy-integration-using-cli.md)
+ [使用 Lambda 代理整合與 OpenAPI 定義設定代理資源](api-gateway-set-up-lambda-proxy-integration-on-proxy-resource.md)

## 了解 API Gateway Lambda 代理整合
<a name="api-gateway-create-api-as-simple-proxy"></a>

Amazon API Gateway Lambda 代理整合是一個簡單、強大且靈活的機制，可透過設定單一 API 方法來建置 API。Lambda 代理整合可讓用戶端在後端呼叫單一 Lambda 函數。函數會存取其他服務的許多資源或功能 AWS ，包括呼叫其他 Lambda 函數。

 在 Lambda 代理整合中，當用戶端提交一個 API 請求時，API Gateway 會對整合的 Lambda 函數傳遞[事件物件](#api-gateway-simple-proxy-for-lambda-input-format)，但不會保留請求參數的順序。此[請求資料](#api-gateway-simple-proxy-for-lambda-input-format)包含請求標頭、查詢字串參數、URL 路徑變數、承載與 API 組態資料。組態資料可包含目前的部署階段名稱、階段變數、使用者身分或授權內容 (如果有)。後端 Lambda 函數會剖析傳入請求資料，以判斷其所傳回的回應。若要讓 API Gateway 將 Lambda 輸出當作 API 回應傳遞至用戶端，Lambda 函數必須以[此格式](#api-gateway-simple-proxy-for-lambda-output-format)傳回結果。

 由於 API Gateway 不用在用戶端與後端 Lambda 函數之間介入太多就可進行 Lambda 代理整合，因此用戶端與整合的 Lambda 函數可以根據彼此的變更進行調整，而不需要中斷 API 的現有整合設定。若要啟用這項功能，用戶端必須遵循後端 Lambda 函數所制定的應用程式通訊協定。

 您可以設定任何 API 方法的 Lambda 代理整合。但針對涉及一般代理資源的 API 方法設定時，Lambda 代理整合會更有效。一般代理資源可由 `{proxy+}` 的特殊樣板化路徑變數、catch-all `ANY` 方法預留位置或兩者來表示。用戶端可以在傳入請求中將輸入當作請求參數或適用的承載傳遞到後端 Lambda 函數。這些請求參數包含標頭、URL 路徑變數、查詢字串參數與適用的承載。整合的 Lambda 函數會驗證所有輸入來源，再處理請求，如果遺失所要求的任何輸入，則會以有意義的錯誤訊息來回應用戶端。

 呼叫與 `ANY` 的泛型 HTTP 方法以及 `{proxy+}` 的一般資源整合的 API 方法時，用戶端會以特定 HTTP 方法取代 `ANY` 來提交請求。用戶端也會指定特定 URL 路徑 (而不是 `{proxy+}`)，並包含任何必要的標頭、查詢字串參數或適用的承載。

 下列清單摘要說明不同 API 方法與 Lambda 代理整合的執行時間行為：
+ `ANY /{proxy+}`：用戶端必須選擇特定 HTTP 方法、必須設定特定資源路徑階層，並可設定任何標頭、查詢字串參數與適用的承載，以將資料作為輸入傳遞至整合的 Lambda 函數。
+ `ANY /res`：用戶端必須選擇特定 HTTP 方法，並可設定任何標頭、查詢字串參數與適用的承載，以將資料作為輸入傳遞至整合的 Lambda 函數。
+ `GET|POST|PUT|... /{proxy+}`：用戶端可設定特定資源路徑階層、任何標頭、查詢字串參數與適用的承載，以將資料作為輸入傳遞至整合的 Lambda 函數。
+  `GET|POST|PUT|... /res/{path}/...`：用戶端必須選擇特定路徑區段 (針對 `{path}` 變數)，並可設定任何請求標頭、查詢字串參數與適用的承載，以將輸入資料傳遞至整合的 Lambda 函數。
+  `GET|POST|PUT|... /res`：用戶端可選擇任何請求標頭、查詢字串參數與適用的承載，以將輸入資料傳遞至整合的 Lambda 函數。

 `{proxy+}` 的代理資源與 `{custom}` 的自訂資源都可使用樣板化路徑變數來表示。不過，`{proxy+}` 可參考沿著路徑階層的任何資源，但 `{custom}` 只能參考特定路徑區段。例如，雜貨店可能會依部門名稱、產品類別與產品類型，來組織其線上產品庫存。雜貨店的網站可接著透過自訂資源的下列樣板化路徑變數來表示可用的產品：`/{department}/{produce-category}/{product-type}`。例如，蘋果是以 `/produce/fruit/apple` 表示，而紅蘿蔔是以 `/produce/vegetables/carrot` 表示。它也可以使用 `/{proxy+}` 來表示客戶在線上商店購物時可搜尋的任何部門、任何產品類別或任何產品類型。例如，`/{proxy+}` 可參考下列任何項目：
+ `/produce`
+ `/produce/fruit`
+ `/produce/vegetables/carrot`

 若要讓客戶搜尋任何可用的產品、其產品類別與相關聯的商店部門，您可以公開 `GET /{proxy+}` 的單一方法並授予唯讀許可。同樣地，若要讓主管更新 `produce` 部門的庫存，您可以設定 `PUT /produce/{proxy+}` 的另一個單一方法並授予讀取/寫入許可。若要讓出納員更新蔬菜的計算加總，您可以設定 `POST /produce/vegetables/{proxy+}` 方法並授予讀取/寫入許可。若要讓商店經理對任何可用的產品執行任何可能的動作，線上商店開發人員可以公開 `ANY /{proxy+}` 方法並授予讀取/寫入許可。在任何情況下，客戶或員工都必須在執行階段選取所選部門中指定類型的特定產品、所選部門中的特定產品類別或特定部門。



如需設定 API Gateway 代理整合的詳細資訊，請參閱[設定代理整合與代理資源](api-gateway-set-up-simple-proxy.md)。

 代理整合需要用戶端更詳細了解後端需求。因此，若要確保最佳應用程式效能與使用者體驗，後端開發人員必須向用戶端開發人員清楚表達後端的需求，並提供未符合需求時的完善錯誤回饋機制。

## 支援多值標頭和查詢字串參數
<a name="apigateway-multivalue-headers-and-parameters"></a>

API Gateway 現在支援具有相同名稱的多個標頭和查詢字串參數。多值標頭以及單值標頭和參數可在相同的請求和回應中結合使用。如需詳細資訊，請參閱[代理整合之 Lambda 函數的輸入格式](#api-gateway-simple-proxy-for-lambda-input-format)及[代理整合之 Lambda 函數的輸出格式](#api-gateway-simple-proxy-for-lambda-output-format)。

## 代理整合之 Lambda 函數的輸入格式
<a name="api-gateway-simple-proxy-for-lambda-input-format"></a>

在 Lambda 代理整合中，API Gateway 會將整個用戶端請求映射至後端 Lambda 函數的輸入 `event` 參數。下列範例顯示 API Gateway 傳送至 Lambda 代理整合之事件的結構。

在此範例中，我們假設 API Gateway 的調用如下：

```
curl 'https://a1b2c3.execute-api.us-east-1.amazonaws.com/my/path?parameter1=value1&parameter2=value1&parameter2=value2&parameter3=value1,value2' -H 'header1: value1' -H 'header2: value1' -H 'header2: value2' -H 'header3: value1,value2'
```

輸出看起來如下：

```
{
  "resource": "/my/path",
  "path": "/my/path",
  "httpMethod": "GET",
  "headers": {
      "header1": "value1",
      "header2": "value2",
      "header3": "value1,value2"
  },
  "multiValueHeaders": {
    "header1": ["value1"],
    "header2": ["value1","value2"],
    "header3": ["value1,value2"]
  },
  "queryStringParameters": {
      "parameter1": "value1",
      "parameter2": "value2",
      "parameter3": "value1,value2"
  },
  "multiValueQueryStringParameters": {
    "parameter1": ["value1"],
    "parameter2": ["value1","value2"],
    "parameter3": ["value1,value2"]
  },
  "requestContext": {
    "accountId": "123456789012",
    "apiId": "id",
    "authorizer": {
      "claims": null,
      "scopes": null
    },
    "domainName": "id.execute-api.us-east-1.amazonaws.com",
    "domainPrefix": "id",
    "extendedRequestId": "request-id",
    "httpMethod": "GET",
    "identity": {
      "accessKey": null,
      "accountId": null,
      "caller": null,
      "cognitoAuthenticationProvider": null,
      "cognitoAuthenticationType": null,
      "cognitoIdentityId": null,
      "cognitoIdentityPoolId": null,
      "principalOrgId": null,
      "sourceIp": "IP",
      "user": null,
      "userAgent": "user-agent",
      "userArn": null,
      "clientCert": {
        "clientCertPem": "CERT_CONTENT",
        "subjectDN": "www.example.com",
        "issuerDN": "Example issuer",
        "serialNumber": "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1",
        "validity": {
          "notBefore": "May 28 12:30:02 2019 GMT",
          "notAfter": "Aug  5 09:36:04 2021 GMT"
        }
      }
    },
    "path": "/my/path",
    "protocol": "HTTP/1.1",
    "requestId": "id=",
    "requestTime": "04/Mar/2020:19:15:17 +0000",
    "requestTimeEpoch": 1583349317135,
    "resourceId": null,
    "resourcePath": "/my/path",
    "stage": "$default"
  },
  "pathParameters": null,
  "stageVariables": null,
  "body": "Hello from Lambda!",
  "isBase64Encoded": false
}
```

**注意**  
在輸入中：  
`headers` 鍵只能包含單一值標頭。
`multiValueHeaders` 鍵可以包含多值標頭以及單一值標頭。
如果您同時指定 `headers` 和 `multiValueHeaders` 的值，API Gateway 會將它們合併成一個清單。如果在兩者指定了相同的鍵值對，則只有 `multiValueHeaders` 中的值會出現在合併清單。

在後端 Lambda 函數的輸入中，`requestContext` 物件是索引鍵/值組的映射。在各對中，鍵是 [$context](api-gateway-mapping-template-reference.md#context-variable-reference) 變數屬性的名稱，而值是該屬性的值。API Gateway 可能會將新的金鑰加入至地圖。

根據啟用的功能，`requestContext` 映射可能會因 API 而不同。例如，在上述範例中，未指定任何授權類型，因此沒有 `$context.authorizer.*` 或 `$context.identity.*` 屬性存在。指定授權類型時，這會導致 API Gateway 將授權的使用者資訊傳遞至 `requestContext.identity` 物件中的整合端點，如下所示：
+ 當授權類型為 `AWS_IAM` 時，授權的使用者資訊包含 `$context.identity.*` 屬性。
+ 當授權類型為 `COGNITO_USER_POOLS` (Amazon Cognito 授權方) 時，授權的使用者資訊包含 `$context.identity.cognito*` 和 `$context.authorizer.claims.*` 屬性。
+ 當授權類型為 `CUSTOM` (Lambda 授權方) 時，授權的使用者資訊包含 `$context.authorizer.principalId` 和其他適用的 `$context.authorizer.*` 屬性。

## 代理整合之 Lambda 函數的輸出格式
<a name="api-gateway-simple-proxy-for-lambda-output-format"></a>

在 Lambda 代理整合中，API Gateway 需要後端 Lambda 函數根據下列 JSON 格式傳回輸出：

```
{
    "isBase64Encoded": {{true|false}},
    "statusCode": {{httpStatusCode}},
    "headers": { "{{headerName}}": "{{headerValue}}", ... },
    "multiValueHeaders": { "{{headerName}}": ["{{headerValue}}", "{{headerValue2}}", ...], ... },
    "body": "{{...}}"
}
```

在輸出中：
+ 如果不再傳回額外的回應標頭，則可以不指定 `headers` 和 `multiValueHeaders` 鍵。
+ `headers` 鍵只能包含單一值標頭。
+ `multiValueHeaders` 鍵可以包含多值標頭以及單一值標頭。您可以使用 `multiValueHeaders` 鍵來指定所有額外標頭，包括任何單一值標頭。
+ 如果您同時指定 `headers` 和 `multiValueHeaders` 的值，API Gateway 會將它們合併成一個清單。如果在兩者指定了相同的鍵值對，則只有 `multiValueHeaders` 中的值會出現在合併清單。

若要啟用 CORS 進行 Lambda 代理整合，您必須將 `Access-Control-Allow-Origin:{{domain-name}}` 新增至輸出 `headers`。`{{domain-name}}` 可以是 `*`，其代表任何網域名稱。輸出 `body` 會封送處理至前端，以做為方法回應承載。如果 `body` 是二進位 Blob，您可以透過將 `isBase64Encoded` 設定為 `true`將其編碼為 Base64 編碼字串，並將 `*/*` 設定為 **Binary Media Type (二進位媒體類型)**。否則，您可以將它設定為 `false`，或保留未指定。

**注意**  
如需啟用二進位支援的詳細資訊，請參閱[使用 API Gateway 主控台啟用二進位支援](api-gateway-payload-encodings-configure-with-console.md)。如需 Lambda 函數的範例，請參閱[在 API Gateway 中從 Lambda 代理整合傳回二進位媒體](lambda-proxy-binary-media.md)。

如果函數輸出的格式不同，則 API Gateway 會傳回 `502 Bad Gateway` 錯誤回應。

若要在 Node.js 的 Lambda 函數中傳回回應，您可以使用以下命令：
+ 若要傳回成功結果，請呼叫 `callback(null, {"statusCode": 200, "body": "results"})`。
+ 若要擲回例外狀況，請呼叫 `callback(new Error('internal server error'))`。
+ 針對用戶端錯誤 (例如，如果遺失必要參數)，您可以呼叫 `callback(null, {"statusCode": 400, "body": "Missing parameters of ..."})` 傳回錯誤，而不擲回例外狀況。

在 Node.js 的 Lambda `async` 函數中，同等語法應為：
+ 若要傳回成功結果，請呼叫 `return {"statusCode": 200, "body": "results"}`。
+ 若要擲回例外狀況，請呼叫 `throw new Error("internal server error")`。
+ 針對用戶端錯誤 (例如，如果遺失必要參數)，您可以呼叫 `return {"statusCode": 400, "body": "Missing parameters of ..."}` 傳回錯誤，而不擲回例外狀況。