

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

# 在 API Gateway 中建立 WebSocket API 的路由
<a name="websocket-api-develop-routes"></a>

在 WebSocket API 中，是根據您設定的路由將傳入 JSON 訊息導向到後端整合。(會將非 JSON 訊息導向您設定的 `$default` 路由。)

*路由*包含的*路由金鑰*，是您可以在*路由選擇表達式*經評估後即預期的值。`routeSelectionExpression` 是在 API 層級定義的屬性。它指定的 JSON 屬性預計會出現在訊息承載。如需路由選擇表達式的詳細資訊，請參閱[路由選擇表達式](#apigateway-websocket-api-route-selection-expressions)。

例如，如果您的 JSON 訊息包含 `action` 屬性，以及您想要根據此屬性執行不同動作，路由選擇表達式可能會 `${request.body.action}`。您的路由表將指定要執行哪一個動作，方法是將 `action` 屬性值與您在資料表中定義的自訂路由鍵值進行比對。

有三種預先定義的路由可供使用：`$connect`、`$disconnect` 和 `$default`。此外，您可以建立自訂路由。
+ API Gateway 會在用戶端和 WebSocket API 之間的持續連線進行起始化時呼叫 `$connect` 路由。
+ 當用戶端或伺服器中斷與 API 的連線時，API Gateway 會呼叫 `$disconnect` 路由。
+ 若發現相符的路由，針對該訊息評估路由選擇運算式後，API Gateway 即會呼叫自訂路由；該比對會判斷要叫用哪些整合。
+ 如果未發現相符路由，或無法針對該訊息來評估路由選擇表達式時，API Gateway 會呼叫 `$default` 路由。

## 路由選擇表達式
<a name="apigateway-websocket-api-route-selection-expressions"></a>

本服務針對傳入訊息選擇欲遵循的路由時，將評估*路由選擇表達式*。本服務將使用 `routeKey` 與評估值完全相符的路由。若無相符路由，且某路由存在 `$default` 路由金鑰，將選取該路由。若沒有路由符合評估值，而且沒有 `$default` 路由，本服務將回傳錯誤。以 WebSocket 型的 API 而言，表達式的形式應為 `$request.body.{path_to_body_element}`。

例如，假設您正傳送下列 JSON 訊息：

```
{
    "service" : "chat",
    "action" : "join",
    "data" : {
        "room" : "room1234"
   }
}
```

您可能想要根據 `action` 屬性來選取您的 API 行為。此時，您可以定義下列路由選擇表達式：

```
$request.body.action
```

此範例中，`request.body` 係指您訊息的 JSON 承載，而 `.action` 則為 [JSONPath](https://goessner.net/articles/JsonPath/) 表達式。`request.body` 之後可使用任何 JSON 路徑表達式，但請記住結果會字串化。例如，若您的 JSONPath 表達式回傳兩個元素的陣列，該結果將以字串 `"[item1, item2]"` 呈現。有鑑於此，理想做法是將表達式的評估結果設為一個值，而非陣列或物件。

您可僅使用靜態值，或者也可以使用多個變數。下表為上述承載的範例及其評估結果。


| 表達式 | 評估結果 | 描述 | 
| --- | --- | --- | 
| \$1request.body.action | join | 未包裝的變數 | 
| \$1\$1request.body.action\$1 | join | 已包裝的變數 | 
| \$1\$1request.body.service\$1/\$1\$1request.body.action\$1 | chat/join | 具備靜態值的多個變數 | 
| \$1\$1request.body.action\$1-\$1\$1request.body.invalidPath\$1  | join- | 若未找到 JSONPath，則變數將解析為 ""。 | 
| action | action | 靜態值 | 
| \$1\$1default | \$1default | 靜態值 | 

評估結果將用於尋找路由。若某路由具備相符的路由金鑰，將選取該路由來處理訊息。若找不到相符的路由，則 API Gateway 會嘗試尋找 `$default` 路由 (如有)。若未定義 `$default` 路由，則 API Gateway 會傳回錯誤。

## 在 API Gateway 中設定 WebSocket API 的路由
<a name="apigateway-websocket-api-routes"></a>

首次新建的 WebSocket API 有三個預先定義的路由：`$connect`、`$disconnect` 和 `$default`，您可以使用 主控台、API 或 建立它們 AWS CLI。如有需要，您可以建立自訂路由。如需更多詳細資訊，請參閱 [API Gateway 中的 WebSocket API 概觀](apigateway-websocket-api-overview.md)。

**注意**  
在 CLI 中，您可在建立整合之前或之後建立路由，也可以在多個路由重複使用相同整合。

### 使用 API Gateway 主控台建立路由
<a name="apigateway-websocket-api-route-using-console"></a>

**使用 API Gateway 主控台建立路由**

1. 登入 API Gateway 主控台、選擇 API，然後選擇 **Routes (路由)**。

1. 選擇**建立路由**。

1. 針對**路由金鑰**，輸入路由金鑰名稱。您可以建立預先定義的路由 (`$connect`、`$disconnect` 和 `$default`)，或是自訂路由。
**注意**  
建立自訂路由時，請勿在路由金鑰名稱字首使用 `$`。此字首保留供預先定義路由使用。

1. 選取並設定路由的整合類型。如需詳細資訊，請參閱[使用 API Gateway 主控台設定 WebSocket API 整合請求](apigateway-websocket-api-integration-requests.md#apigateway-websocket-api-integration-request-using-console)。

### 使用 建立路由 AWS CLI
<a name="apigateway-websocket-api-route-using-awscli"></a>

以下 [create-route](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-route.html) 命令會建立路由：

```
aws apigatewayv2 --region us-east-1 create-route --api-id aabbccddee --route-key $default
```

輸出將如下所示：

```
{
    "ApiKeyRequired": false,
    "AuthorizationType": "NONE",
    "RouteKey": "$default",
    "RouteId": "1122334"
}
```

### 指定 `$connect` 的路由請求設定
<a name="apigateway-websocket-api-route-request-connect"></a>

設定 API 的 `$connect` 路由時，可使用下列選用設定，以啟用您 API 的授權。如需更多詳細資訊，請參閱 [`$connect` 路由](apigateway-websocket-api-route-keys-connect-disconnect.md#apigateway-websocket-api-routes-about-connect)。
+ **Authorization (授權)**：若無須授權，可指定為 `NONE`。否則，您可指定：
  + `AWS_IAM` 使用標準 AWS IAM 政策來控制對 API 的存取。
  + `CUSTOM`，以指定您之前建立的 Lambda 授權方函數，藉此實作 API 的授權。授權方可以位於您自己的 AWS 帳戶或其他 AWS 帳戶中。如需 Lambda 授權方的詳細資訊，請參閱 [使用 API Gateway Lambda 授權方](apigateway-use-lambda-authorizer.md)。
**注意**  
在 API Gateway 主控台中，只有在您設定授權方函數 (如 `CUSTOM` 所述) 後，才會看到 [設定 Lambda 授權方 (主控台)](configure-api-gateway-lambda-authorization.md#configure-api-gateway-lambda-authorization-with-console) 設定。
**重要**  
**Authorization (授權)** 設定會套用至整個 API，不只是 `$connect` 路由。`$connect` 路由會保護其他路由，因為每次連線都會呼叫該路由。
+ **API Key Required (需要 API 金鑰)**：API 的 `$connect` 路由可選擇要求 API 金鑰。您可以同時使用 API 金鑰與用量計劃，以控制並追蹤對 API 的存取。如需更多詳細資訊，請參閱 [API Gateway 中 REST API 的用量計畫和 API 金鑰](api-gateway-api-usage-plans.md)。

### 使用 API Gateway 主控台設定 `$connect` 路由請求
<a name="apigateway-websocket-api-connect-route-request-using-console"></a>

若要使用 API Gateway 主控台來設定 WebSocket API 的 `$connect` 路由請求：

1. 登入 API Gateway 主控台、選擇 API，然後選擇 **Routes (路由)**。

1. 在**路由**下，選擇 `$connect`，或依照 [使用 API Gateway 主控台建立路由](#apigateway-websocket-api-route-using-console) 建立 `$connect` 路由。

1. 在**路由請求設定**區段中，選擇**編輯**。

1. 針對**授權**，選取授權類型。

1. 若要針對 `$connect` 路由要求 API，請選取**需要 API 金鑰**。

1. 選擇**儲存變更**。

# 在 API Gateway 中設定 WebSocket API 的路由回應
<a name="apigateway-websocket-api-route-response"></a>

WebSocket 路由可設定為雙向或單向通訊。API Gateway 不會將後端回應傳遞至路由回應，除非您有設定路由回應。

**注意**  
您只能定義 WebSocket API 的 `$default` 路由回應。您可以使用整合回應來操作後端服務的回應。如需詳細資訊，請參閱[整合回應概觀](apigateway-websocket-api-integration-responses.md#apigateway-websocket-api-integration-response-overview)。

您可以使用 API Gateway 主控台或 AWS CLI 或 AWS SDK 來設定路由回應和回應選取表達式。

如需路由回應選擇表達式的詳細資訊，請參閱 [路由回應選擇表達式](apigateway-websocket-api-selection-expressions.md#apigateway-websocket-api-route-response-selection-expressions)。

**Topics**
+ [使用 API Gateway 主控台設定路由回應](#apigateway-websocket-api-route-response-using-console)
+ [使用 設定路由回應 AWS CLI](#apigateway-websocket-api-route-response-using-awscli)

## 使用 API Gateway 主控台設定路由回應
<a name="apigateway-websocket-api-route-response-using-console"></a>

建立 WebSocket API 並將代理 Lambda 函數附加至預設路由之後，您可以使用 API Gateway 主控台設定路由回應：

1. 登入 API Gateway 主控台，在 `$default` 路由上選擇具備代理 Lambda 函數整合的 WebSocket API。

1. 在 **Routes** (路由) 下選擇 `$default` 路由。

1. 選擇**啟用雙向通訊**。

1. 選擇**部署 API**。

1. 將您的 API 部署至階段。

 使用下列 [ wscat](https://www.npmjs.com/package/wscat) 命令來連線到您的 API。如需 `wscat` 的相關資訊，請參閱 [使用 `wscat` 以連接到 WebSocket API 和將訊息傳送到其中](apigateway-how-to-call-websocket-api-wscat.md)。

```
wscat -c wss://api-id.execute-api.us-east-2.amazonaws.com/test
```

 按下 Enter 按鈕以呼叫預設路由。您 Lambda 函數的主體應該會傳回。

## 使用 設定路由回應 AWS CLI
<a name="apigateway-websocket-api-route-response-using-awscli"></a>

以下 [create-route-response](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-route-response.html) 命令會建立 `$default` 路由的路由回應。您可以使用 [get-apis](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/get-apis.html) 和 [get-routes](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/get-routes.html) 命令來識別 API ID 和路由 ID。

```
aws apigatewayv2 create-route-response \
    --api-id aabbccddee \
    --route-id 1122334  \
    --route-response-key '$default'
```

輸出將如下所示：

```
{
    "RouteResponseId": "abcdef",
    "RouteResponseKey": "$default"
}
```

# 設定需要 WebSocket 子協定的 `$connect` 路由
<a name="websocket-connect-route-subprotocol"></a>

用戶端可以使用 `Sec-WebSocket-Protocol` 欄位在連線到您的 WebSocket API 期間請求一個 [WebSocket 子通訊協定](https://datatracker.ietf.org/doc/html/rfc6455#page-12)。您可以設定 `$connect` 路由整合，以允許只有在用戶端請求您的 API 支援的子通訊協定時才允許連線。

下列範例 Lambda 函數會將 `Sec-WebSocket-Protocol` 標題傳回用戶端。只有在用戶端指定 `myprotocol` 子協議時，該函數才會建立到您的 API 的連線。

如需建立此範例 API 和 Lambda 代理整合的 CloudFormation 範本，請參閱 [samples/ws-subprotocol.zip](samples/ws-subprotocol.zip)。

```
export const handler = async (event) => {
    if (event.headers != undefined) {
        const headers = toLowerCaseProperties(event.headers);
        
        if (headers['sec-websocket-protocol'] != undefined) {
            const subprotocolHeader = headers['sec-websocket-protocol'];
            const subprotocols = subprotocolHeader.split(',');
            
            if (subprotocols.indexOf('myprotocol') >= 0) {
                const response = {
                    statusCode: 200,
                    headers: {
                        "Sec-WebSocket-Protocol" : "myprotocol"
                    }
                };
                return response;
            }
        }
    }
    
    const response = {
        statusCode: 400
    };
        
    return response;
};

function toLowerCaseProperties(obj) {
    var wrapper = {};
    for (var key in obj) {
        wrapper[key.toLowerCase()] = obj[key];
    }
    return wrapper;
}
```

您可以使用 [https://www.npmjs.com/package/wscat](https://www.npmjs.com/package/wscat) 來測試 API 是否允許連線，但只有在用戶端要求您的 API 支援的子通訊協定時才可以。下列命令會使用 `-s` 旗標來指定連線期間的子通訊協定。

下列命令會嘗試使用不受支援的子通訊協定進行連線。因為用戶端指定 `chat1` 子通訊協定，Lambda 整合會傳回 400 錯誤訊息，而且連線失敗。

```
wscat -c wss://api-id.execute-api.region.amazonaws.com/beta -s chat1
error: Unexpected server response: 400
```

下列命令在連線要求中包含支援的子通訊協定。Lambda 整合允許連線。

```
wscat -c wss://api-id.execute-api.region.amazonaws.com/beta -s chat1,myprotocol
connected (press CTRL+C to quit)
```

若要進一步了解如何叫用 WebSocket API，請參閱[調用 WebSocket API](apigateway-how-to-call-websocket-api.md)。