

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

# 在 中使用即時資料應用程式的訂閱 AWS AppSync
<a name="aws-appsync-real-time-data"></a>

**重要**  
自 2025 年 3 月 13 日起，您可以使用 AWS AppSync Events 建置由 WebSockets 支援的即時 PubSub API。如需詳細資訊，請參閱《AppSync Events 開發人員指南》中的[透過 WebSocket 發佈](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)事件。 *AWS AppSync *

AWS AppSync 可讓您利用訂閱來實作即時應用程式更新、推送通知等。當用戶端叫用 GraphQL 訂閱操作時， AWS AppSync 會自動建立和維護安全的 WebSocket 連線。應用程式接著可以即時將資料從資料來源分發給訂閱者，同時 AWS AppSync 會持續管理應用程式的連線和擴展需求。以下各節將向您展示 in AWS AppSync 訂閱的運作方式。

## GraphQL 結構描述訂閱指令
<a name="graphql-schema-subscription-directives"></a>

訂閱 in AWS AppSync 被調用為對變動的回應。這表示您可以在變動上指定 GraphQL 結構描述指令，讓任何資料來源 in AWS AppSync 即時。

 AWS Amplify 用戶端程式庫會自動處理訂閱連線管理。這些程式庫使用純 WebSockets 做為用戶端和服務之間的網路通訊協定。

**注意**  
若要控制訂閱的連線時間授權，您可以使用 AWS Identity and Access Management (IAM) AWS Lambda、Amazon Cognito 身分集區或 Amazon Cognito 使用者集區進行欄位層級授權。對於訂閱的精細存取控制，您可以將解析程式連接至訂閱欄位，並使用發起人身分和 AWS AppSync 資料來源執行邏輯。如需詳細資訊，請參閱[設定授權和身分驗證來保護 GraphQL APIs](security-authz.md)。

會從變動觸發訂閱且會將變動選擇設定傳送給訂閱者。

以下範例示範如何使用 GraphQL 訂閱。它不會指定資料來源，因為資料來源可以是 Lambda、Amazon DynamoDB 或 Amazon OpenSearch Service。

若要開始使用訂閱，您必須將訂閱進入點新增至您的結構描述，如下所示：

```
schema {
    query: Query
    mutation: Mutation
    subscription: Subscription
}
```

假設您有一個部落格文章網站，以及您想要訂閱新部落格和變更現有的部落格。若要執行此操作，請將以下 `Subscription` 定義新增至結構描述：

```
type Subscription {
    addedPost: Post
    updatedPost: Post
    deletedPost: Post
}
```

假設您有以下變動：

```
type Mutation {
    addPost(id: ID! author: String! title: String content: String url: String): Post!
    updatePost(id: ID! author: String! title: String content: String url: String ups: Int! downs: Int! expectedVersion: Int!): Post!
    deletePost(id: ID!): Post!
}
```

您可以透過為您希望接收通知的每個訂閱新增 `@aws_subscribe(mutations: ["mutation_field_1", "mutation_field_2"])` 指示 (如下所示) 讓這些欄位變得即時：

```
type Subscription {
    addedPost: Post
    @aws_subscribe(mutations: ["addPost"])
    updatedPost: Post
    @aws_subscribe(mutations: ["updatePost"])
    deletedPost: Post
    @aws_subscribe(mutations: ["deletePost"])
}
```

由於 `@aws_subscribe(mutations: ["",..,""])`採用一系列的變動輸入，因此您可以指定多個變動來啟動訂閱。如果您是從用戶端進行訂閱，您的 GraphQL 查詢可能如下所示：

```
subscription NewPostSub {
    addedPost {
        __typename
        version
        title
        content
        author
        url
    }
}
```

用戶端連線和工具需要此訂閱查詢。

使用純 WebSockets 用戶端時，每個用戶端都會完成選取集篩選，因為每個用戶端都可以定義自己的選取集。在此情況下，訂閱選項集必須是變動選項集的子集。例如，連結至變動 `addPost(...){id author title url version}` 的訂閱 `addedPost{author title}` 僅接收文章的作者和標題。而沒有接收其他欄位。但是，如果變動缺少其選項集中的作者，則訂閱者將取得作者欄位的 `null` 值 (或者如果作者欄位在結構描述中被定義為必要/非 null，則會出現錯誤)。

使用純 WebSockets 時，訂閱選擇集至關重要。如果訂閱中未明確定義欄位，則 AWS AppSync 不會傳回 欄位。

在上述範例中，訂閱沒有引數。假設您的結構描述如下所示：

```
type Subscription {
    updatedPost(id:ID! author:String): Post
    @aws_subscribe(mutations: ["updatePost"])
}
```

在此情況下，您的用戶端定義訂閱如下：

```
subscription UpdatedPostSub {
    updatedPost(id:"XYZ", author:"ABC") {
        title
        content
    }
}
```

在結構描述 `subscription` 欄位的傳回類型必須與對應變動欄位的傳回類型相符。在上述範例中，這是以 `addPost` 類型形式傳回做為 `addedPost` 和 `Post` 而顯示。

若要在用戶端上設定訂閱，請參閱 [使用 Amplify 用戶端建置用戶端應用程式](building-a-client-app.md)。

## 使用訂閱引數
<a name="using-subscription-arguments"></a>

使用 GraphQL 訂閱的重要部分是了解何時及如何使用引數。您可以進行細微的變更，以修改通知用戶端發生變動的方式和時間。若要這樣做，請參閱快速入門章節的範例結構描述，該章節會建立「待辦事項」。對於此範例結構描述，定義了下列變動：

```
type Mutation {
    createTodo(input: CreateTodoInput!): Todo
    updateTodo(input: UpdateTodoInput!): Todo
    deleteTodo(input: DeleteTodoInput!): Todo
}
```

在預設範例中，用戶端可以使用`Todo``onUpdateTodo``subscription`沒有引數的 訂閱任何 的更新：

```
subscription OnUpdateTodo {
  onUpdateTodo {
    description
    id
    name
    when
  }
}
```

您可以使用其引數`subscription`來篩選您的 。例如，若要只在更新`todo`具有特定 `ID`的 `subscription`時觸發 ，請指定 `ID`值：

```
subscription OnUpdateTodo {
  onUpdateTodo(id: "a-todo-id") {
    description
    id
    name
    when
  }
}
```

您也可以傳遞多個引數。例如，以下`subscription`示範如何在特定位置和時間收到任何`Todo`更新的通知：

```
subscription todosAtHome {
  onUpdateTodo(when: "tomorrow", where: "at home") {
    description
    id
    name
    when
    where
  }
}
```

請注意，所有引數都是選用的。如果您未在 中指定任何引數`subscription`，則會訂閱應用程式中發生的所有`Todo`更新。不過，您可以更新 `subscription`的欄位定義，以要求 `ID`引數。這將強制特定 的回應，`todo`而不是所有 `todo`：

```
onUpdateTodo(
  id: ID!,
  name: String,
  when: String,
  where: String,
  description: String
): Todo
```

### 引數 Null 值具有意義
<a name="argument-null-value-has-meaning"></a>

進行訂閱查詢 in AWS AppSync 時，`null`引數值的篩選結果會與完全省略引數不同。

讓我們回到可建立待辦事項的待辦事項 API 範例。請參閱快速入門章節中的範例結構描述。

讓我們修改結構描述，在 `Todo`類型中包含描述擁有者身分的新`owner`欄位。欄位不是必要`owner`欄位，只能在 上設定`UpdateTodoInput`。請參閱下列簡化版本的結構描述：

```
type Todo {
  id: ID!
  name: String!
  when: String!
  where: String!
  description: String!
  owner: String
}

input CreateTodoInput {
  name: String!
  when: String!
  where: String!
  description: String!
}

input UpdateTodoInput {
  id: ID!
  name: String
  when: String
  where: String
  description: String
  owner: String
}

type Subscription {
    onUpdateTodo(
        id: ID,
        name: String,
        when: String,
        where: String,
        description: String
    ): Todo @aws_subscribe(mutations: ["updateTodo"])
}
```

下列訂閱會傳回所有`Todo`更新：

```
subscription MySubscription {
  onUpdateTodo {
    description
    id
    name
    when
    where
  }
}
```

如果您修改上述訂閱以新增欄位引數 `owner: null`，您現在會詢問不同的問題。此訂閱現在會註冊用戶端，以收到尚未提供擁有者的所有`Todo`更新通知。

```
subscription MySubscription {
  onUpdateTodo(owner: null) {
    description
    id
    name
    when
    where
  }
}
```

**注意**  
**自 2022 年 1 月 1 日起，MQTT over WebSockets 不再提供做為 GraphQL 訂閱 AWS AppSync APIs通訊協定。Pure WebSockets 是 中唯一支援的通訊協定 AWS AppSync。**  
以 AWS AppSync SDK 或 Amplify 程式庫為基礎的用戶端，在 2019 年 11 月之後發行，預設會自動使用純 WebSockets 將用戶端升級至最新版本可讓用戶端使用 AWS AppSync純 WebSockets 引擎。  
Pure WebSockets 隨附更大的承載大小 (240 KB)、更廣泛的用戶端選項，以及改善的 CloudWatch 指標。如需使用純 WebSocket 用戶端的詳細資訊，請參閱 [建置即時 WebSocket 用戶端 in AWS AppSync](real-time-websocket-client.md)。

# 在 中建立由無伺服器 WebSockets提供支援的一般 pub/sub APIs AWS AppSync
<a name="aws-appsync-real-time-create-generic-api-serverless-websocket"></a>

**重要**  
自 2025 年 3 月 13 日起，您可以使用 AWS AppSync Events 建置由 WebSockets 支援的即時 PubSub API。如需詳細資訊，請參閱《AppSync Events 開發人員指南》中的[透過 WebSocket 發佈](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)事件。 *AWS AppSync *

有些應用程式只需要簡單的 WebSocket APIs其中用戶端會接聽特定的頻道或主題。沒有特定形狀或強烈類型需求的一般 JSON 資料可以推送到以純且簡單的發佈訂閱 (pub/sub) 模式收聽這些頻道之一的用戶端。

Use AWS AppSync 透過在 APIs 後端和用戶端上自動產生 GraphQL 程式碼，在幾分鐘內實作幾乎沒有 GraphQL 知識的簡單 pub/sub WebSocket API。 GraphQL 

## 建立和設定 pub-sub APIs
<a name="aws-appsync-real-time-enhanced-filtering-using-pub-sub-apis"></a>

若要開始使用，請執行下列動作：

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在**儀表板**上，選擇 **Create API (建立 API)**。

1. 在下一個畫面上，選擇**建立即時 API**，然後選擇**下一步**。

1. 為您的 pub/sub API 輸入易記的名稱。

1. 您可以啟用[私有 API](https://docs.aws.amazon.com/appsync/latest/devguide/using-private-apis.html) 功能，但我們建議暫時將其關閉。選擇**下一步**。

1. 您可以選擇使用 WebSockets 自動產生運作中的 pub/sub API。目前也建議您關閉此功能。選擇**下一步**。

1. 選擇**建立 API**，然後等待幾分鐘。將在您的帳戶中建立新的預先設定 AWS AppSync pub/sub API AWS 。

API 使用 AWS AppSync 的內建本機解析程式 （如需使用本機解析程式的詳細資訊，請參閱*AWS AppSync 開發人員指南*》中的[教學課程：本機解析程式](https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-local-resolvers-js.html)) 來管理多個臨時 pub/sub 通道和 WebSocket 連線，這些連線只會根據頻道名稱自動將資料交付和篩選至訂閱的用戶端。使用 API 金鑰授權 API 呼叫。

部署 API 之後，您會收到幾個額外的步驟來產生用戶端程式碼，並將其與您的用戶端應用程式整合。如需如何快速整合用戶端的範例，本指南將使用簡單的 React Web 應用程式。

1. 首先在本機電腦上使用 [NPM](https://www.npmjs.com/get-npm) 建立樣板 React 應用程式：

   ```
   $ npx create-react-app mypubsub-app 
   $ cd mypubsub-app
   ```
**注意**  
此範例使用 [Amplify 程式庫](https://docs.amplify.aws/lib/)將用戶端連線至後端 API。不過，您不需要在本機建立 Amplify CLI 專案。雖然 React 是此範例中選擇的用戶端，但 Amplify 程式庫也支援 iOS、Android 和 Flutter 用戶端，在這些不同的執行時間中提供相同的功能。支援的 Amplify 用戶端提供簡單的抽象概念，以幾行程式碼與 AWS AppSync GraphQL API 後端互動，包括內建 WebSocket 功能，完全相容於 [AWS AppSync 即時 WebSocket 通訊協定](https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html)：  

   ```
   $ npm install @aws-amplify/api
   ```

1. 在 AWS AppSync 主控台中，選取 **JavaScript**，然後選取**下載**以下載具有 API 組態詳細資訊和產生 GraphQL 操作程式碼的單一檔案。

1. 將下載的檔案複製到 React 專案中的 `/src` 資料夾。

1. 接著，將現有樣板`src/App.js`檔案的內容取代為 主控台中可用的範例用戶端程式碼。

1. 使用下列命令在本機啟動應用程式：

   ```
   $ npm start
   ```

1. 若要測試傳送和接收即時資料，請開啟兩個瀏覽器視窗並存取 *localhost：3000*。範例應用程式設定為將一般 JSON 資料傳送至名為*機器人的*硬式編碼頻道。

1.  在其中一個瀏覽器視窗中，在文字方塊中輸入下列 JSON Blob，然後按一下**提交**：

   ```
   {
     "robot":"r2d2",
     "planet": "tatooine"
   }
   ```

這兩個瀏覽器執行個體都會訂閱*機器人*頻道，並即時接收發佈的資料，顯示在 Web 應用程式底部：

![\[pub/sub API 的 React 應用程式範例\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/pub-sub-react.png)


系統會自動產生所有必要的 GraphQL API 程式碼，包括結構描述、解析程式和操作，以啟用一般 pub/sub 使用案例。在後端，資料會發佈至具有 GraphQL 變動的 AWS AppSync 即時端點，如下所示：

```
mutation PublishData {
    publish(data: "{\"msg\": \"hello world!\"}", name: "channel") {
        data
        name
    }
}
```

訂閱者會使用相關的 GraphQL 訂閱存取傳送至特定臨時頻道的已發佈資料：

```
subscription SubscribeToData {
    subscribe(name:"channel") {
        name
        data
    }
}
```

## 在現有應用程式中實作 pub-sub APIs
<a name="aws-appsync-real-time-enhanced-filtering-existing-apps"></a>

如果您只需要在現有應用程式中實作即時功能，這個一般 pub/sub API 組態可以輕鬆整合到任何應用程式或 API 技術。雖然使用單一 API 端點與 GraphQL 在單一網路呼叫中安全地存取、操作和合併來自一或多個資料來源的資料，但不需要從頭轉換或重建現有的 REST 型應用程式，以利用 AWS AppSync 的即時功能。例如，您可以在單獨的 API 端點中擁有現有的 CRUD 工作負載，用戶端只會將訊息或事件從現有應用程式傳送到一般 pub/sub API，以用於即時和 pub/sub 目的。

# 在 中定義增強型訂閱篩選條件 AWS AppSync
<a name="aws-appsync-real-time-enhanced-filtering"></a>

**重要**  
自 2025 年 3 月 13 日起，您可以使用 AWS AppSync Events 建置由 WebSockets 支援的即時 PubSub API。如需詳細資訊，請參閱《AppSync Events 開發人員指南》中的[透過 WebSocket 發佈](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)事件。 *AWS AppSync *

在 中 AWS AppSync，您可以使用支援其他邏輯運算子的篩選條件，直接在 GraphQL API 訂閱解析程式中定義和啟用後端資料篩選的商業邏輯。您可以設定這些篩選條件，與用戶端中訂閱查詢上定義的訂閱引數不同。如需使用訂閱引數的詳細資訊，請參閱 [使用訂閱引數](aws-appsync-real-time-data.md#using-subscription-arguments)。如需運算子清單，請參閱 [AWS AppSync 解析程式映射範本公用程式參考](resolver-util-reference.md)。

基於本文件的目的，我們會將即時資料篩選分為下列類別：
+ **基本篩選** - 根據訂閱查詢中的用戶端定義引數進行篩選。
+ **增強型篩選** - 根據 AWS AppSync 服務後端中集中定義的邏輯進行篩選。

下列各節說明如何設定增強型訂閱篩選條件，並顯示其實際用途。

## 在 GraphQL 結構描述中定義訂閱
<a name="aws-appsync-real-time-enhanced-filtering-using-subscription-filters"></a>

若要使用增強型訂閱篩選條件，請在 GraphQL 結構描述中定義訂閱，然後使用篩選延伸來定義增強型篩選條件。若要說明增強型訂閱篩選的運作方式 AWS AppSync，請使用下列 GraphQL 結構描述，其定義票證管理系統 API，例如：

```
type Ticket {
	id: ID
	createdAt: AWSDateTime
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
	status: String
	
}

type Mutation {
	createTicket(input: TicketInput): Ticket
}

type Query {
	getTicket(id: ID!): Ticket
}

type Subscription {
	onSpecialTicketCreated: Ticket @aws_subscribe(mutations: ["createTicket"])
	onGroupTicketCreated(group: String!): Ticket @aws_subscribe(mutations: ["createTicket"])
}



enum Priority {
	none
	lowest
	low
	medium
	high
	highest
}

input TicketInput {
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
```

假設您為 API 建立`NONE`資料來源，然後使用此資料來源將解析程式連接到`createTicket`變動。您的處理常式可能如下所示：

```
import { util } from '@aws-appsync/utils';

export function request(ctx) {
	return {
		payload: {
			id: util.autoId(),
			createdAt: util.time.nowISO8601(),
			status: 'pending',
			...ctx.args.input,
		},
	};
}

export function response(ctx) {
	return ctx.result;
}
```

**注意**  
增強型篩選條件會在指定訂閱的 GraphQL 解析程式處理常式中啟用。如需詳細資訊，請參閱[解析程式參考](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-js-version.html)。

若要實作增強型篩選條件的行為，您必須使用 `extensions.setSubscriptionFilter()`函數來定義篩選條件表達式，根據訂閱用戶端可能感興趣的 GraphQL 變動所發佈的資料進行評估。如需篩選延伸模組的詳細資訊，請參閱[延伸模組](https://docs.aws.amazon.com//appsync/latest/devguide/extensions-js.html)。

下一節說明如何使用篩選延伸來實作增強型篩選條件。

## 使用篩選延伸項目建立增強型訂閱篩選條件
<a name="aws-appsync-real-time-enhanced-filtering-defining-filters"></a>

增強型篩選條件會以 JSON 寫入訂閱解析程式的回應處理常式中。篩選條件可以分組在稱為 的清單中`filterGroup`。篩選條件是使用至少一個規則來定義，每個規則都有欄位、運算子和值。讓我們為 定義新的解析程式`onSpecialTicketCreated`，以設定增強型篩選條件。您可以在使用 AND 邏輯評估的篩選條件中設定多個規則，而篩選群組中的多個篩選條件則使用 OR 邏輯評估：

```
import { util, extensions } from '@aws-appsync/utils';

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = {
		or: [
			{ severity: { ge: 7 }, priority: { in: ['high', 'medium'] } },
			{ category: { eq: 'security' }, group: { in: ['admin', 'operators'] } },
		],
	};
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));

  // important: return null in the response
	return null;
}
```

根據上述範例中定義的篩選條件，如果票證是以下列方式建立，則會自動將重要票證推送至訂閱的 API 用戶端：
+ `priority` 關卡`high`或 `medium`

  AND 
+ `severity` 層級大於或等於 `7`(`ge`)

或 
+ `classification` 票證設定為 `Security` 

  AND 
+ `group` 指派設定為 `admin`或 `operators`

![\[顯示票證篩選查詢的範例\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/aws-priority-example.png)


訂閱解析程式中定義的篩選條件 （增強篩選） 優先於僅根據訂閱引數進行篩選 （基本篩選）。如需使用訂閱引數的詳細資訊，請參閱[使用訂閱引數](https://docs.aws.amazon.com//appsync/latest/devguide/aws-appsync-real-time-data.html#using-subscription-arguments))。

如果在訂閱的 GraphQL 結構描述中定義和需要 引數，則只有在引數在解析程式的 `extensions.setSubscriptionFilter()`方法中定義為規則時，才會根據指定的引數進行篩選。不過，如果訂閱解析程式中沒有`extensions`篩選方法，則用戶端中定義的引數只會用於基本篩選。您無法同時使用基本篩選和增強型篩選。

您可以使用訂閱篩選條件延伸邏輯中的 [`context`變數](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)來存取請求的相關內容資訊。例如，使用 Amazon Cognito 使用者集區、OIDC 或 Lambda 自訂授權方進行授權時，您可以在建立訂閱`context.identity`時擷取 中使用者的相關資訊。您可以使用該資訊，根據使用者的身分建立篩選條件。

現在假設您想要實作 的增強型篩選條件行為`onGroupTicketCreated`。`onGroupTicketCreated` 訂閱需要強制`group`名稱做為 引數。建立時，票證會自動指派`pending`狀態。您可以設定訂閱篩選條件，只接收屬於所提供群組的新建立票證：

```
import { util, extensions } from '@aws-appsync/utils';

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = { group: { eq: ctx.args.group }, status: { eq: 'pending' } };
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));

	return null;
}
```

使用如下範例中的變動發佈資料時：

```
mutation CreateTicket {
  createTicket(input: {priority: medium, severity: 2, group: "aws"}) {
    id
    priority
    severity
    status
    group
    createdAt
  }
}
```

一旦建立具有`createTicket`變動的票證，訂閱的用戶端就會監聽透過 WebSockets 自動推送的資料：

```
subscription OnGroup {
  onGroupTicketCreated(group: "aws") {
    category
    status
    severity
    priority
    id
    group
    createdAt
    content
  }
}
```

無需引數即可訂閱用戶端，因為篩選邏輯是在 AWS AppSync 服務中使用增強型篩選實作，可簡化用戶端程式碼。只有在符合定義的篩選條件時，用戶端才會接收資料。

## 定義巢狀結構描述欄位的增強型篩選條件
<a name="aws-appsync-real-time-enhanced-filters-nested-schema-fields.title"></a>

您可以使用增強型訂閱篩選來篩選巢狀結構描述欄位。假設我們修改了上一節的結構描述，以包含位置和地址類型：

```
type Ticket {
	id: ID
	createdAt: AWSDateTime
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
	status: String
	location: ProblemLocation
}

type Mutation {
	createTicket(input: TicketInput): Ticket
}

type Query {
	getTicket(id: ID!): Ticket
}

type Subscription {
	onSpecialTicketCreated: Ticket @aws_subscribe(mutations: ["createTicket"])
	onGroupTicketCreated(group: String!): Ticket @aws_subscribe(mutations: ["createTicket"])
}

type ProblemLocation {
	address: Address
}

type Address {
	country: String
}

enum Priority {
	none
	lowest
	low
	medium
	high
	highest
}

input TicketInput {
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
	location: AWSJSON
```

透過此結構描述，您可以使用`.`分隔符號來表示巢狀化。下列範例會在 下新增巢狀結構描述欄位的篩選規則`location.address.country`。如果票證的地址設定為 ，則會觸發訂閱`USA`：

```
import { util, extensions } from '@aws-appsync/utils';

export const request = (ctx) => ({ payload: null });

export function response(ctx) {
	const filter = {
		or: [
			{ severity: { ge: 7 }, priority: { in: ['high', 'medium'] } },
			{ category: { eq: 'security' }, group: { in: ['admin', 'operators'] } },
			{ 'location.address.country': { eq: 'USA' } },
		],
	};
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));
	return null;
}
```

在上述範例中， `location`代表巢狀層級一， `address` 代表巢狀層級二， `country`代表巢狀層級三，所有這些都由`.`分隔符號分隔。

您可以使用 `createTicket`變動測試此訂閱：

```
mutation CreateTicketInUSA {
  createTicket(input: {location: "{\"address\":{\"country\":\"USA\"}}"}) {
    category
    content
    createdAt
    group
    id
    location {
      address {
        country
      }
    }
    priority
    severity
    status
  }
}
```

## 從用戶端定義增強型篩選條件
<a name="aws-appsync-real-time-enhanced-filtering-defining-from-client"></a>

您可以在 GraphQL 中使用基本篩選搭配[訂閱引數](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html#using-subscription-arguments)。在訂閱查詢中進行呼叫的用戶端會定義引數的值。在具有`extensions`篩選條件的 AWS AppSync 訂閱解析程式中啟用增強型篩選條件時，解析程式中定義的後端篩選條件會優先且優先。

使用訂閱中的`filter`引數設定動態、用戶端定義的增強型篩選條件。設定這些篩選條件時，您必須更新 GraphQL 結構描述以反映新引數：

```
...
type Subscription {
    onSpecialTicketCreated(filter: String): Ticket
        @aws_subscribe(mutations: ["createTicket"])
}
...
```

然後，用戶端可以傳送訂閱查詢，如下列範例所示：

```
subscription onSpecialTicketCreated($filter: String) {
     onSpecialTicketCreated(filter: $filter) {
        id
        group
        description
        priority
        severity
     }
 }
```

您可以設定查詢變數，如下列範例所示：

```
{"filter" : "{\"severity\":{\"le\":2}}"}
```

`util.transform.toSubscriptionFilter()` 解析程式公用程式可在訂閱回應映射範本中實作，以套用每個用戶端訂閱引數中定義的篩選條件：

```
import { util, extensions } from '@aws-appsync/utils';

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = ctx.args.filter;
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));
	return null;
}
```

透過此策略，用戶端可以定義自己的篩選條件，使用增強型篩選邏輯和其他運算子。當指定的用戶端在安全的 WebSocket 連線中調用訂閱查詢時，會指派篩選條件。如需增強型篩選之轉換公用程式的詳細資訊，包括`filter`查詢變數承載的格式，請參閱 [JavaScript 解析程式概觀](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)。

## 其他增強型篩選限制
<a name="aws-appsync-real-time-enhanced-filtering-additional-restrictions"></a>

以下是幾個使用案例，其中對增強型篩選條件施加了額外的限制：
+ 增強型篩選條件不支援篩選最上層物件清單。在此使用案例中，增強型訂閱會忽略來自變動的已發佈資料。
+ AWS AppSync 最多支援五個巢狀層級。將忽略巢狀層級 5 以上結構描述欄位的篩選條件。使用以下 GraphQL 回應。`venue.address.country.metadata.continent` 允許 中的 `continent` 欄位，因為它是層級 5 巢狀。不過， `financial` `venue.address.country.metadata.capital.financial`是第六層巢狀，因此篩選條件無法運作：

  ```
  {
      "data": {
          "onCreateFilterEvent": {
              "venue": {
                  "address": {
                      "country": {
                          "metadata": {
                              "capital": {
                                  "financial": "New York"
                              },
                              "continent" : "North America"
                          }
                      },
                      "state": "WA"
                  },
                  "builtYear": 2023
              },
              "private": false,
          }
      }
  }
  ```

# 在 中使用篩選條件取消訂閱 WebSocket 連線 AWS AppSync
<a name="aws-appsync-real-time-invalidation"></a>

**重要**  
自 2025 年 3 月 13 日起，您可以使用 AWS AppSync Events 建置由 WebSockets 支援的即時 PubSub API。如需詳細資訊，請參閱《AppSync Events 開發人員指南》中的[透過 WebSocket 發佈](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)事件。 *AWS AppSync *

在 中 AWS AppSync，您可以根據特定篩選邏輯，強制取消訂閱並關閉 （驗證） 已連線用戶端的 WebSocket 連線。這在授權相關案例中非常有用，例如當您從群組中移除使用者時。

訂閱失效是為了回應變動中定義的承載。我們建議您將用於使訂閱連線失效的變動視為 API 中的管理操作，並藉由限制其對管理員使用者、群組或後端服務的使用來相應地範圍許可。例如，使用結構描述授權指令，例如 `@aws_auth(cognito_groups: ["Administrators"])`或 `@aws_iam`。如需詳細資訊，請參閱[使用其他授權模式](https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html#using-additional-authorization-modes)。

失效篩選條件使用與[增強型訂閱篩選條件](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-enhanced-filtering.html)相同的語法和邏輯。使用下列公用程式定義這些篩選條件：
+ `extensions.invalidateSubscriptions()` – 在 GraphQL 解析程式的變動回應處理常式中定義。
+ `extensions.setSubscriptionInvalidationFilter()` – 在連結至變動之訂閱的 GraphQL 解析程式回應處理常式中定義。

如需失效篩選延伸模組的詳細資訊，請參閱 [JavaScript 解析程式概觀](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)。

## 使用訂閱失效
<a name="aws-appsync-real-time-invalidation-using-invalidations"></a>

若要查看訂閱失效的運作方式 AWS AppSync，請使用下列 GraphQL 結構描述：

```
type User {
  userId: ID!
  groupId: ID!
}
    
type Group {
  groupId: ID!
  name: String!
  members: [ID!]!
}

type GroupMessage {
  userId: ID!
  groupId: ID!
  message: String!
}

type Mutation {
    createGroupMessage(userId: ID!, groupId : ID!, message: String!): GroupMessage
    removeUserFromGroup(userId: ID!, groupId : ID!) : User @aws_iam
}

type Subscription {
    onGroupMessageCreated(userId: ID!, groupId : ID!): GroupMessage
        @aws_subscribe(mutations: ["createGroupMessage"])
}

type Query {
	none: String
}
```

在`removeUserFromGroup`變動解析程式程式碼中定義失效篩選條件：

```
import { extensions } from '@aws-appsync/utils';

export function request(ctx) {
	return { payload: null };
}

export function response(ctx) {
	const { userId, groupId } = ctx.args;
	extensions.invalidateSubscriptions({
		subscriptionField: 'onGroupMessageCreated',
		payload: { userId, groupId },
	});
	return { userId, groupId };
}
```

調用變動時， `payload` 物件中定義的資料會用來取消訂閱 中定義的訂閱`subscriptionField`。失效篩選條件也會在`onGroupMessageCreated`訂閱的回應映射範本中定義。

如果`extensions.invalidateSubscriptions()`承載包含的 ID 符合篩選條件中定義的訂閱用戶端 IDs，則會取消訂閱對應的訂閱。此外，WebSocket 連線已關閉。定義訂閱的`onGroupMessageCreated`訂閱解析程式程式碼：

```
import { util, extensions } from '@aws-appsync/utils';

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = { groupId: { eq: ctx.args.groupId } };
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));

	const invalidation = { groupId: { eq: ctx.args.groupId }, userId: { eq: ctx.args.userId } };
	extensions.setSubscriptionInvalidationFilter(util.transform.toSubscriptionFilter(invalidation));

	return null;
}
```

請注意，訂閱回應處理常式可以同時定義訂閱篩選條件和失效篩選條件。

例如，假設用戶端 A `group-1`使用以下訂閱請求，將 ID 為 的新使用者訂閱`user-1`至 ID 為 的群組：

```
onGroupMessageCreated(userId : "user-1", groupId: :"group-1"){...}
```

AWS AppSync 會執行訂閱解析程式，產生上述`onGroupMessageCreated`回應映射範本中定義的訂閱和失效篩選條件。對於用戶端 A，訂閱篩選條件僅允許將資料傳送至 `group-1`，並同時為 `user-1`和 定義失效篩選條件`group-1`。

現在假設用戶端 B `group-2`使用以下訂閱請求，將 ID 為 的使用者訂閱`user-2`至 ID 為 的群組：

```
onGroupMessageCreated(userId : "user-2", groupId: :"group-2"){...}
```

AWS AppSync 會執行訂閱解析程式，產生訂閱和失效篩選條件。對於用戶端 B，訂閱篩選條件僅允許將資料傳送至 `group-2`，並同時為 `user-2`和 定義失效篩選條件`group-2`。

接著，假設具有 ID 的新群組訊息`message-1`是使用變動請求建立，如下列範例所示：

```
createGroupMessage(id: "message-1", groupId :
      "group-1", message: "test message"){...}
```

符合已定義篩選條件的訂閱用戶端會透過 WebSockets 自動接收下列資料承載：

```
{
  "data": {
    "onGroupMessageCreated": {
      "id": "message-1",
      "groupId": "group-1",
      "message": "test message",
    }
  }
}
```

用戶端 A 會收到訊息，因為篩選條件符合定義的訂閱篩選條件。不過，用戶端 B 不會收到訊息，因為使用者不屬於 `group-1`。此外，請求不符合訂閱解析程式中定義的訂閱篩選條件。

最後，假設 `user-1` `group-1`使用以下變動請求從 中移除：

```
removeUserFromGroup(userId: "user-1", groupId : "group-1"){...}
```

變動會啟動其`extensions.invalidateSubscriptions()`解析程式回應處理常式程式碼中定義的訂閱失效。 AWS AppSync 然後取消訂閱用戶端 A 並關閉其 WebSocket 連線。用戶端 B 不受影響，因為變動中定義的失效承載與其使用者或群組不相符。

當連線 AWS AppSync 失效時，用戶端會收到確認已取消訂閱的訊息：

```
{
  "message": "Subscription complete."
}
```

## 在訂閱失效篩選條件中使用內容變數
<a name="aws-appsync-real-time-invalidation-context"></a>

如同增強型訂閱篩選條件，您可以在訂閱失效篩選條件延伸中使用 [`context`變數](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)來存取特定資料。

例如，您可以將電子郵件地址設定為變動中的失效承載，然後將其與使用 Amazon Cognito 使用者集區或 OpenID Connect 授權之訂閱使用者的電子郵件屬性或宣告進行比對。`extensions.setSubscriptionInvalidationFilter()` 訂閱失效程式中定義的失效篩選條件會檢查變動`extensions.invalidateSubscriptions()`承載設定的電子郵件地址是否與 中使用者 JWT 字符擷取的電子郵件地址相符`context.identity.claims.email`，進而啟動失效。

# 建置即時 WebSocket 用戶端 in AWS AppSync
<a name="real-time-websocket-client"></a>

**重要**  
自 2025 年 3 月 13 日起，您可以使用 AWS AppSync Events 建置由 WebSockets 支援的即時 PubSub API。如需詳細資訊，請參閱《AppSync Events 開發人員指南》中的[透過 WebSocket 發佈](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)事件。 *AWS AppSync *

AWS AppSync 的即時 WebSocket 用戶端可透過多步驟程序啟用 GraphQL 訂閱。用戶端會先與 AWS AppSync 即時端點建立 WebSocket 連線、傳送連線初始化訊息，並等待確認。成功連線後，用戶端會透過傳送具有唯一 IDs和 GraphQL 查詢的開始訊息來註冊訂閱。 AWS AppSync 會以確認訊息確認成功訂閱。然後，用戶端會接聽由對應變動觸發的訂閱事件。為了維持連線， AWS AppSync 會定期傳送保持連線訊息。完成後，用戶端會透過傳送停止訊息來取消註冊訂閱。此系統支援單一 WebSocket 連線上的多個訂閱，並容納各種授權模式，包括 API 金鑰、Amazon Cognito 使用者集區、IAM 和 Lambda。

## GraphQL 訂閱的即時 WebSocket 用戶端實作
<a name="appsynclong-real-time-websocket-client-implementation-guide-for-graphql-subscriptions"></a>

下列序列圖和步驟顯示 WebSocket 用戶端、HTTP 用戶端和 AWS AppSync 之間的即時訂閱工作流程。

![\[Sequence diagram showing WebSocket client, AppSync endpoints, and HTTP client interactions for real-time subscriptions.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/realtime-client-flow.png)


1. 用戶端會與 AWS AppSync 即時端點建立 WebSocket 連線。如果存在網路錯誤，用戶端應該執行抖動的指數輪詢。如需詳細資訊，請參閱 AWS 架構部落格上的[指數退避和抖動](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)。

1. （選用） 成功建立 WebSocket 連線後，用戶端會傳送訊息`connection_init`。

1. 如果 `connection_init` 已傳送，用戶端會等待來自 AWS AppSync `connection_ack`的訊息。此訊息包含 `connectionTimeoutMs` 參數，這是 `"ka"`（保持連線） 訊息的最大等待時間，以毫秒為單位。

1. AWS AppSync 會定期`"ka"`傳送訊息。用戶端會追蹤收到每則`"ka"`訊息的時間。如果用戶端未在`connectionTimeoutMs`幾毫秒內收到`"ka"`訊息，用戶端應該關閉連線。

1. 用戶端會透過傳送訂閱訊息來註冊 `start` 訂閱。單一 WebSocket 連線支援多個訂閱，即使它們處於不同的授權模式。

1. 用戶端等待 AWS AppSync `start_ack`傳送訊息以確認訂閱成功。如果發生錯誤， AWS AppSync 會傳回`"type": "error"`訊息。

1. 用戶端會接聽訂閱事件，這些事件會在呼叫對應的變動後傳送。查詢和變動通常會透過 `https://` 傳送至 AWS AppSync GraphQL 端點。訂閱會使用安全的 WebSocket () 流經 AWS AppSync 即時端點`wss://`。

1. 用戶端會透過傳送訂閱訊息來取消註冊 `stop` 訂閱。

1. 取消註冊所有訂閱並檢查沒有透過 WebSocket 傳輸的訊息後，用戶端可以斷開與 WebSocket 的連線。

## 建立 WebSocket 連線的交握詳情
<a name="handshake-details-to-establish-the-websocket-connection"></a>

若要使用 AWS AppSync 連接和啟動成功的交握，WebSocket 用戶端需要下列項目：
+ The AWS AppSync 即時端點
+ 標頭 – 包含與 AWS AppSync 端點和授權相關的資訊。 AWS AppSync 支援以下三種提供標頭的方法：
  + 透過查詢字串的標頭
    + 標頭資訊編碼為 base64 字串，衍生自字串化 JSON 物件。此 JSON 物件包含與 AWS AppSync 端點和授權相關的詳細資訊。JSON 物件的內容會根據授權模式而有所不同。
  + 透過 的標頭 `Sec-WebSocket-Protocol`
    + 來自字串化 JSON 物件的 base64Url-encoded字串，其中包含與 AWS AppSync 端點和授權相關的資訊，會在 `Sec-WebSocket-Protocol`標頭中做為通訊協定傳遞。JSON 物件的內容會根據授權模式而有所不同。
  + 透過標準 HTTP 標頭的標頭：
    + 標頭可以作為連線請求中的標準 HTTP 標頭傳遞，類似於 GraphQL 查詢和變動至 AWS AppSync 的標頭傳遞方式。不過，私有 API 連線請求不支援透過標準 HTTP 標頭傳遞標頭。
+  `payload` – Base64-encoded字串`payload`。只有在使用查詢字串提供標頭時，才需要承載

透過這些需求，WebSocket 用戶端可以連線至 URL，其中包含具有查詢字串的即時端點，使用 `graphql-ws`做為 WebSocket 通訊協定。

### 從 GraphQL 端點探索 即時端點
<a name="discovering-the-appsync-real-time-endpoint-from-the-appsync-graphql-endpoint"></a>

通訊協定和網域中的 AWS AppSync GraphQL 端點和 AWS AppSync 即時端點略有不同。您可以使用 AWS Command Line Interface (AWS CLI) 命令 擷取 GraphQL 端點`aws appsync get-graphql-api`。

****AWS AppSync GraphQL 端點：****  
 `https://example1234567890000.appsync-api.us-east-1.amazonaws.com/graphql`

****AWS AppSync 即時端點：****  
 `wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql`

應用程式可以使用任何 HTTP 用戶端來連線至 AWS AppSync GraphQL 端點 (`https://`) 進行查詢和變動。應用程式可以使用訂閱的任何 WebSocket 用戶端連線到 AWS AppSync 即時端點 (`wss://`)。

使用自訂網域名稱，您可以使用單一網域與兩個端點互動。例如，如果您將 `api.example.com`設定為自訂網域，則可以使用這些 URLs 與 GraphQL 和即時端點互動：

**AWS AppSync 自訂網域 GraphQL 端點：**  
`https://api.example.com/graphql`

**AWS AppSync 自訂網域即時端點：**  
`wss://api.example.com/graphql/realtime`

## 以 AWS AppSync API 授權模式為基礎的標頭參數格式
<a name="header-parameter-format-based-on-appsync-api-authorization-mode"></a>

連線查詢字串中使用的`header`物件格式會根據 AWS AppSync API 授權模式而有所不同。物件中的 `host` 欄位是指 AWS AppSync GraphQL 端點，即使對即時端點進行`wss://`呼叫，也會用來驗證連線。若要啟動交握並建立授權連線，`payload` 應該是空的 JSON 物件。只有在標頭透過查詢字串傳遞時，才需要承載。

下列各節示範每個授權模式的標頭格式。

### API 金鑰
<a name="api-key"></a>

#### API 金鑰標頭
<a name="api-key-list"></a>

**標頭內容**
+  `"host": <string>`： AWS AppSync GraphQL 端點的主機或您的自訂網域名稱。
+  `"x-api-key": <string>`：為 AWS AppSync API 設定的 API 金鑰。

**範例**

```
{
    "host":"example1234567890000.appsync-api.us-east-1.amazonaws.com",
    "x-api-key":"da2-12345678901234567890123456"
}
```

**透過查詢字串的標頭**

首先，包含 `host`和 的 JSON 物件`x-api-key`會轉換為字串。接下來，此字串會使用 base64 編碼進行編碼。產生的 base64 編碼字串會新增為名為 WebSocket URL `header`的查詢參數，以建立與 AWS AppSync 即時端點的連線。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJob3N0IjoiZXhhbXBsZTEyMzQ1Njc4OTAwMDAuYXBwc3luYy1hcGkudXMtZWFzdC0xLmFtYXpvbmF3cy5jb20iLCJ4LWFtei1kYXRlIjoiMjAyMDA0MDFUMDAxMDEwWiIsIngtYXBpLWtleSI6ImRhMi16NHc0NHZoczV6Z2MzZHRqNXNranJsbGxqaSJ9&payload=e30=
```

請務必注意，除了 base64 編碼的標頭物件之外，空的 JSON 物件 \$1\$1 也是 base64 編碼的，並包含在 WebSocket URL `payload`中做為名為 的個別查詢參數。

**透過 的標頭 `Sec-WebSocket-Protocol`**

包含 `host`和 的 JSON 物件`x-api-key`會轉換為字串，然後使用 base64Url 編碼進行編碼。產生的 base64Url-encoded字串字首為 `header-`。在與 AWS AppSync 即時端點建立 WebSocket 連線時，除了 `Sec-WebSocket-Protocol`標頭`graphql-ws`中的 之外，此字首字串也會用作新的子通訊協定。

產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 標頭包含下列值：

```
"sec-websocket-protocol" : ["graphql-ws", "header-ewogICAgImhvc3QiOiJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsCiAgICAieC1hcGkta2V5IjoiZGEyLTEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Igp9"]
```

**透過標準 HTTP 標頭的標頭**

在此方法中，在與 AWS AppSync 即時端點建立 WebSocket 連線時，會使用標準 HTTP 標頭傳輸主機和 API 金鑰資訊。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

請求標頭會包含下列項目：

```
"sec-websocket-protocol" : ["graphql-ws"]
"host":"example1234567890000.appsync-api.us-east-1.amazonaws.com",
"x-api-key":"da2-12345678901234567890123456"
```

### Amazon Cognito 使用者集區和 OpenID 連線 (OIDC)
<a name="amazon-cognito-user-pools-and-openid-connect-oidc"></a>

#### Amazon Cognito 和 OIDC 標頭
<a name="amazon-cognito-user-pools-and-openid-connect-oidc-list"></a>

標頭內容：
+  `"Authorization": <string>`：JWT ID 字符。標頭可以使用[承載結構](https://datatracker.ietf.org/doc/html/rfc6750#section-2.1)描述。
+  `"host": <string>`： AWS AppSync GraphQL 端點的主機或您的自訂網域名稱。

範例：

```
{
    "Authorization":"eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJHWEFLSXBieU5WNHhsQjEXAMPLEnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyEXAMPLEiJhNmNmMjcwNy0xNjgxLTQ1NDItOWYxOC1lNjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImVkMzM5MmNkLWNjYTMtNGM2OC1hNDYyLTJlZGI3ZTNmY2FjZiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk0NTc3MTgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zb3V0aGVhc3QtMl83OHY0SVZibVAiLCJleHAiOjE1Njk0NjEzMjAsImlhdCI6MTU2OTQ1NzcyMCwianRpIjoiNTgzZjhmYmMtMzk2MS00YzA4LWJhZTAtYzQyY2IxMTM5NDY5IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1N3RoZWw0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3EXAMPLEn0.B4EXAMPLEFNpJ6ikVp7e6DRee95V6Qi-zEE2DJH7sHOl2zxYi7f-SmEGoh2AD8emxQRYajByz-rE4Jh0QOymN2Ys-ZIkMpVBTPgu-TMWDyOHhDUmUj2OP82yeZ3wlZAtr_gM4LzjXUXmI_K2yGjuXfXTaa1mvQEBG0mQfVd7SfwXB-jcv4RYVi6j25qgow9Ew52ufurPqaK-3WAKG32KpV8J4-Wejq8t0c-yA7sb8EnB551b7TU93uKRiVVK3E55Nk5ADPoam_WYE45i3s5qVAP_-InW75NUoOCGTsS8YWMfb6ecHYJ-1j-bzA27zaT9VjctXn9byNFZmEXAMPLExw",
    "host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
}
```

**透過查詢字串的標頭**

首先，包含 `host`和 的 JSON 物件`Authorization`會轉換為字串。接下來，此字串會使用 base64 編碼進行編碼。產生的 base64 編碼字串會新增為名為 WebSocket URL `header`的查詢參數，以建立與 AWS AppSync 即時端點的連線。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

請務必注意，除了 base64 編碼的標頭物件之外，空的 JSON 物件 \$1\$1 也是 base64 編碼的，並包含在 WebSocket URL `payload`中做為名為 的個別查詢參數。

**透過 的標頭 `Sec-WebSocket-Protocol`**

包含 `host`和 的 JSON 物件`Authorization`會轉換為字串，然後使用 base64Url 編碼進行編碼。產生的 base64Url-encoded字串字首為 `header-`。在與 AWS AppSync 即時端點建立 WebSocket 連線時，除了 `Sec-WebSocket-Protocol`標頭`graphql-ws`中的 之外，此字首字串也會用作新的子通訊協定。

產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 標頭包含下列值：

```
"sec-websocket-protocol" : ["graphql-ws", "header-ewogICAgImhvc3QiOiJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsCiAgICAieC1hcGkta2V5IjoiZGEyLTEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Igp9"]
```

**透過標準 HTTP 標頭的標頭**

在此方法中，在與 AWS AppSync 即時端點建立 WebSocket 連線時，會使用標準 HTTP 標頭傳輸主機和授權資訊。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

請求標頭會包含下列項目：

```
"sec-websocket-protocol" : ["graphql-ws"]
"Authorization":"eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJHWEFLSXBieU5WNHhsQjEXAMPLEnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyEXAMPLEiJhNmNmMjcwNy0xNjgxLTQ1NDItOWYxOC1lNjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImVkMzM5MmNkLWNjYTMtNGM2OC1hNDYyLTJlZGI3ZTNmY2FjZiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk0NTc3MTgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zb3V0aGVhc3QtMl83OHY0SVZibVAiLCJleHAiOjE1Njk0NjEzMjAsImlhdCI6MTU2OTQ1NzcyMCwianRpIjoiNTgzZjhmYmMtMzk2MS00YzA4LWJhZTAtYzQyY2IxMTM5NDY5IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1N3RoZWw0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3EXAMPLEn0.B4EXAMPLEFNpJ6ikVp7e6DRee95V6Qi-zEE2DJH7sHOl2zxYi7f-SmEGoh2AD8emxQRYajByz-rE4Jh0QOymN2Ys-ZIkMpVBTPgu-TMWDyOHhDUmUj2OP82yeZ3wlZAtr_gM4LzjXUXmI_K2yGjuXfXTaa1mvQEBG0mQfVd7SfwXB-jcv4RYVi6j25qgow9Ew52ufurPqaK-3WAKG32KpV8J4-Wejq8t0c-yA7sb8EnB551b7TU93uKRiVVK3E55Nk5ADPoam_WYE45i3s5qVAP_-InW75NUoOCGTsS8YWMfb6ecHYJ-1j-bzA27zaT9VjctXn9byNFZmEXAMPLExw",
"host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
```

### IAM
<a name="iam"></a>

#### IAM 標頭
<a name="iam-list"></a>

**標頭內容**
+  `"accept": "application/json, text/javascript"`：常數 `<string>` 參數。
+  `"content-encoding": "amz-1.0"`：常數 `<string>` 參數。
+  `"content-type": "application/json; charset=UTF-8"`：常數 `<string>` 參數。
+  `"host": <string>`：這是 AWS AppSync GraphQL 端點的主機。
  + `"x-amz-date": <string>`：時間戳記必須是 UTC 和下列 ISO 8601 格式：YYYYMMDD'T'HHMMSS'Z'。例如，20150830T123600Z 是有效的時間戳記。不包含時間戳記的毫秒數。如需詳細資訊，請參閱《[》中的 Signature 第 4 版中的處理日期](https://docs.aws.amazon.com/general/latest/gr/sigv4-date-handling.html)*AWS 一般參考*。
  +  `"X-Amz-Security-Token": <string>`： AWS 工作階段字符，使用臨時安全登入資料時需要。如需詳細資訊，請參閱《IAM 使用者指南》**中的[搭配使用暫時憑證與 AWS 資源](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_credentials_temp_use-resources.html)。
  +  `"Authorization": <string>`： AWS AppSync 端點的簽章第 4 版 (SigV4) 簽署資訊。如需簽署程序的詳細資訊，請參閱《》中的[任務 4：將簽章新增至 HTTP 請求](https://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html)*AWS 一般參考*。

SigV4 簽署 HTTP 請求包含正式 URL，這是`/connect`附加 的 AWS AppSync GraphQL 端點。服務端點 AWS 區域與您使用 AWS AppSync API 的區域相同，且服務名稱為 'appsync'。要簽署的 HTTP 請求如下：

```
{
  url: "https://example1234567890000.appsync-api.us-east-1.amazonaws.com/graphql/connect",
  data: "{}",
  method: "POST",
  headers: {
    "accept": "application/json, text/javascript",
    "content-encoding": "amz-1.0",
    "content-type": "application/json; charset=UTF-8",
  }
}
```

**範例**

```
{
  "accept": "application/json, text/javascript",
  "content-encoding": "amz-1.0",
  "content-type": "application/json; charset=UTF-8",
  "host": "example1234567890000.appsync-api.us-east-1.amazonaws.com",
  "x-amz-date": "20200401T001010Z",
  "X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
  "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=83EXAMPLEbcc1fe3ee69f75cd5ebbf4cb4f150e4f99cec869f149c5EXAMPLEdc"
}
```

**透過查詢字串的標頭**

首先，包含 `host`(AWS AppSync GraphQL 端點） 和其他授權標頭的 JSON 物件會轉換為字串。接下來，此字串會使用 base64 編碼進行編碼。產生的 base64 編碼字串會新增至 WebSocket URL，做為名為 的查詢參數`header`。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

請務必注意，除了 base64 編碼的標頭物件之外，空的 JSON 物件 \$1\$1 也是 base64 編碼的，並包含在 WebSocket URL `payload`中做為名為 的個別查詢參數。

**透過 的標頭 `Sec-WebSocket-Protocol`**

包含 和其他授權標頭`host`的 JSON 物件會轉換為字串，然後使用 base64Url 編碼進行編碼。產生的 base64Url-encoded字串字首為 `header-`。在與 AWS AppSync 即時端點建立 WebSocket 連線時，除了 `Sec-WebSocket-Protocol`標頭`graphql-ws`中的 之外，此字首字串也會用作新的子通訊協定。

產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 標頭包含下列值：

```
"sec-websocket-protocol" : ["graphql-ws", "header-ew0KICAiYWNjZXB0IjogImFwcGxpY2F0aW9uL2pzb24sIHRleHQvamF2YXNjcmlwdCIsDQogICJjb250ZW50LWVuY29kaW5nIjogImFtei0xLjAiLA0KICAiY29udGVudC10eXBlIjogImFwcGxpY2F0aW9uL2pzb247IGNoYXJzZXQ9VVRGLTgiLA0KICAiaG9zdCI6ICJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsDQogICJ4LWFtei1kYXRlIjogIjIwMjAwNDAxVDAwMTAxMFoiLA0KICAiWC1BbXotU2VjdXJpdHktVG9rZW4iOiAiQWdFWEFNUExFWjJsdVgyVmpFQW9hRG1Gd0xYTnZkWFJvWldGRVhBTVBMRWN3UlFJZ0FoOTdDbGpxN3dPUEw4S3N4UDNZdER1eWMvOWhBajhQaEo3RnZmMzhTZ29DSVFEaEpFWEFNUExFUHNwaW9PenRqKytwRWFnV0N2ZVpVaktFbjB6eVVoQkVYQU1QTEVqai8vLy8vLy8vLy84QkVYQU1QTEV4T0RrMk5EZ3lOemcxTlNJTW8xbVducEVTV1VvWXc0QmtLcUVGU3JtM0RYdUw4dytaYlZjNEpLakRQNHZVQ0tOUjZMZTlDOXBacDlQc1cwTm9GeTN2TEJVZEFYRVhBTVBMRU9WRzhmZVhmaUVFQSsxa2hnRksvd0V0d1IrOXpGN05hTU1Nc2UwN3dOMmdHMnRIMGVLTUVYQU1QTEVRWCtzTWJ5dFFvOGllcFA5UFpPemxac1NGYi9kUDVROGhrNllFWEFNUExFWWNLWnNUa0RBcTJ1S0ZROG1ZVVZBOUV0UW5OUmlGTEVZODNhS3ZHL3RxTFdObkdsU05WeDdTTWNmb3ZrRkRxUWFtbSs4OHkxT3d3QUVZSzdxY29jZVg2WjdHR2NhWXVJZkdwYVgyTUNDRUxlUXZaKzhXeEVnT25JZno3R1l2c1lOakxaU2FSblY0RytJTFkxRjBRTlc2NFM5TnZqK0J3RGczaHQyQ3JOdnB3alZZbGo5VTNubXhFMFVHNW5lODNMTDVoaHFNcG0yNWttTDdlblZndzJrUXptVTJpZDRJS3UwQy9XYW9EUnVPMkY1ekU2M3ZKYnhOOEFZczczMzgrNEI0SEJiNkJaNk9VZ2c5NlExNVJBNDEvZ0lxeGFWUHh5VHBEZlRVNUdmU0x4b2NkWWVuaXFxcEZNdFpHMm45ZDB1N0dzUU5jRmtOY0czcURabTR0RG84dFpidXltMGEyVmNGMkU1aEZFZ1hCYStYTEpDZlhpLzc3T3FBRWpQMHg3UWRrM0I0M3A4S0cvQmFpb1A1UnNWOHpCR3ZIMXpBZ3lQaGEyck43MC90VDEzeXJtUGQ1UVlFZnd6ZXhqS3JWNG1XSXVSZzhOVEhZU1pKVWFleUN3VG9tODBWRlVKWEcrR1lUVXl2NVcyMmFCY25vUkdpQ2lLRVlUTE9rZ1hlY2RLRlRIbWNJQWVqUTlXZWxyMGExOTZLcTg3dzVLTk1Da2NDR0Zud0JORkxtZm5icE5xVDZyVUJ4eHMzWDVudFg5ZDhIVnRTWUlOVHNHWFhNWkNKN2ZuYldhamhnL2FveDBGdEhYMjFlRjZxSUdUOGoxeitsMm9wVStnZ3dVZ2toVVVnQ0gyVGZxQmorTUxNVlZ2cGdxSnNQS3Q1ODJjYUZLQXJJRkl2Tys5UXVweExuRUgyaHowNFRNVGZuVTZiUUM2ejFidVZlN2grdE9MbmgxWVBGc0xRODhhbmliLzdUVEM4azlEc0JUcTBBU2U4UjJHYlNFc21POXFiYk13Z0VhWVVoT0t0R2V5UXNTSmRoU2s2WHhYVGhyV0w5RW53QkNYRGtJQ01xZG50QXh5eU05bldzWjRiTDlKSHFFeGdXVW1mV0NoelBGQXFuM0Y0eTg5NlVxSFRaeGxxM1dHeXBuNUhIY2VtMkhxZjNJVnhLSDFpbmhxZFZ0a3J5RWlUV3JJN1pkamJxbnFSYmwrV2d0UHRLT093ZURsQ2FSczNSMnFYY2JOZ1ZobGVNazRJV25GOEQxNjk1QWVuVTFMd0hqT0pMa0NqeGdORmlXQUZFUEg5YUVYQU1QTEV4QT09IiwNCiAgIkF1dGhvcml6YXRpb24iOiAiQVdTNC1ITUFDLVNIQTI1NiBDcmVkZW50aWFsPVhYWFhYWFhYWFhYWFhYWFhYWFgvMjAyMDA0MDEvdXMtZWFzdC0xL2FwcHN5bmMvYXdzNF9yZXF1ZXN0LCBTaWduZWRIZWFkZXJzPWFjY2VwdDtjb250ZW50LWVuY29kaW5nO2NvbnRlbnQtdHlwZTtob3N0O3gtYW16LWRhdGU7eC1hbXotc2VjdXJpdHktdG9rZW4sIFNpZ25hdHVyZT04M0VYQU1QTEViY2MxZmUzZWU2OWY3NWNkNWViYmY0Y2I0ZjE1MGU0Zjk5Y2VjODY5ZjE0OWM1RVhBTVBMRWRjIg0KfQ"]
```

**透過標準 HTTP 標頭的標頭**

在此方法中，在與 AWS AppSync 即時端點建立 WebSocket 連線時，會使用標準 HTTP 標頭傳輸主機和其他授權資訊。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

請求標頭會包含下列項目：

```
"sec-websocket-protocol" : ["graphql-ws"]
"accept": "application/json, text/javascript",
"content-encoding": "amz-1.0",
"content-type": "application/json; charset=UTF-8",
"host": "example1234567890000.appsync-api.us-east-1.amazonaws.com",
"x-amz-date": "20200401T001010Z",
"X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
"Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=83EXAMPLEbcc1fe3ee69f75cd5ebbf4cb4f150e4f99cec869f149c5EXAMPLEdc"
```

若要使用自訂網域簽署請求：

```
{
  url: "https://api.example.com/graphql/connect",
  data: "{}",
  method: "POST",
  headers: {
    "accept": "application/json, text/javascript",
    "content-encoding": "amz-1.0",
    "content-type": "application/json; charset=UTF-8",
  }
}
```

**範例**

```
{
  "accept": "application/json, text/javascript",
  "content-encoding": "amz-1.0",
  "content-type": "application/json; charset=UTF-8",
  "host": "api.example.com",
  "x-amz-date": "20200401T001010Z",
  "X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
  "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=83EXAMPLEbcc1fe3ee69f75cd5ebbf4cb4f150e4f99cec869f149c5EXAMPLEdc"
}
```

**使用查詢字串請求 URL**

```
wss://api.example.com/graphql?header=eyEXAMPLEHQiOiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L2phdmFEXAMPLEQiLCJjb250ZW50LWVuY29kaW5nIjoEXAMPLEEuMCIsImNvbnRlbnQtdHlwZSI6ImFwcGxpY2F0aW9EXAMPLE47IGNoYXJzZXQ9VVRGLTgiLCJob3N0IjoiZXhhbXBsZEXAMPLENjc4OTAwMDAuYXBwc3luYy1hcGkudXMtZWFzdC0xLmFtYEXAMPLEcy5jb20iLCJ4LWFtei1kYXRlIjoiMjAyMDA0MDFUMDAxMDEwWiIsIlgtEXAMPLElY3VyaXR5LVRva2VuIjoiQWdvSmIzSnBaMmx1WDJWakVBb2FEbUZ3TFhOdmRYUm9aV0Z6ZEMweUlrY3dSUUlnQWg5N0NsanE3d09QTDhLc3hQM1l0RHV5Yy85aEFqOFBoSjdGdmYzOFNnb0NJUURoSllKYkpsbmpQc3Bpb096dGorK3BFYWdXQ3ZlWlVqS0VuMHp5VWhCbXhpck5CUWpqLy8vLy8vLy8vLzhCRUFBYUREY3hPRGsyTkRneU56ZzFOU0lNbzFtV25wRVNXVW9ZdzRCa0txRUZTcm0zRFh1TDh3K1piVmM0SktqRFA0dlVDS05SNkxlOUM5cFpwOVBzVzBOb0Z5M3ZMQlVkQVh3dDZQSld1T1ZHOGZlWGZpRUVBKzFraGdGSy93RXR3Uis5ekY3TmFNTU1zZTA3d04yZ0cydEgwZUtNVFhuOEF3QVFYK3NNYnl0UW84aWVwUDlQWk96bFpzU0ZiL2RQNVE4aGs2WWpHVGFMMWVZY0tac1RrREFxMnVLRlE4bVlVVkE5RXRRbk5SaUZMRVk4M2FLdkcvdHFMV05uR2xTTlZ4N1NNY2ZvdmtGRHFRYW1tKzg4eTFPd3dBRVlLN3Fjb2NlWDZaN0dHY2FZdUlmR3BhWDJNQ0NFTGVRdlorOFd4RWdPbklmejdHWXZzWU5qTFpTYVJuVjRHK0lMWTFGMFFOVzY0UzlOdmorQndEZzNodDJDck52cHdqVllsajlVM25teEUwVUc1bmU4M0xMNWhocU1wbTI1a21MN2VuVmd3MmtRem1VMmlkNElLdTBDL1dhb0RSdU8yRjV6RTYzdkpieE44QVlzNzMzOCs0QjRIQmI2Qlo2T1VnZzk2UTE1UkE0MS9nSXF4YVZQeHlUcERmVFU1R2ZTTHhvY2RZZW5pcXFwRk10WkcybjlkMHU3R3NRTmNGa05jRzNxRFptNHREbzh0WmJ1eW0wYTJWY0YyRTVoRkVnWEJhK1hMSkNmWGkvNzdPcUFFalAweDdRZGszQjQzcDhLRy9CYWlvUDVSc1Y4ekJHdkgxekFneVBoYTJyTjcwL3RUMTN5cm1QZDVRWUVmd3pleGpLclY0bVdJdVJnOE5USFlTWkpVYWV5Q3dUb204MFZGVUpYRytHWVRVeXY1VzIyYUJjbm9SR2lDaUtFWVRMT2tnWGVjZEtGVEhtY0lBZWpROVdlbHIwYTE5NktxODd3NUtOTUNrY0NHRm53Qk5GTG1mbmJwTnFUNnJVQnh4czNYNW50WDlkOEhWdFNZSU5Uc0dYWE1aQ0o3Zm5iV2FqaGcvYW94MEZ0SFgyMWVGNnFJR1Q4ajF6K2wyb3BVK2dnd1Vna2hVVWdDSDJUZnFCaitNTE1WVnZwZ3FKc1BLdDU4MmNhRktBcklGSXZPKzlRdXB4TG5FSDJoejA0VE1UZm5VNmJRQzZ6MWJ1VmU3aCt0T0xuaDFZUEZzTFE4OGFuaWIvN1RUQzhrOURzQlRxMEFTZThSMkdiU0VzbU85cWJiTXdnRWFZVWhPS3RHZXlRc1NKZGhTazZYeFhUaHJXTDlFbndCQ1hEa0lDTXFkbnRBeHl5TTluV3NaNGJMOUpIcUV4Z1dVbWZXQ2h6UEZBcW4zRjR5ODk2VXFIVFp4bHEzV0d5cG41SEhjZW0ySHFmM0lWeEtIMWluaHFkVnRrcnlFaVRXckk3WmRqYnFucVJibCtXZ3RQdEtPT3dlRGxDYVJzM1IycVhjYk5nVmhsZU1rNElXbkY4RDE2OTVBZW5VMUx3SGpPSkxrQ2p4Z05GaVdBRkVQSDlhTklhcXMvWnhBPT0iLCJBdXRob3JpemF0aW9uIjoiQVdTNC1ITUFDLVNIQTI1NiBDcmVkZW50aWFsPVhYWFhYWFhYWFhYWFhYWFhYWFgvMjAxOTEwMDIvdXMtZWFzdC0xEXAMPLE5bmMvYXdzNF9yZXF1ZXN0LCBTaWduZWRIZWFkZXJzPWFjY2VwdDtjb250ZWEXAMPLE29kaW5nO2NvbnRlbnQtdHlwZTtob3EXAMPLEW16LWRhdGU7eC1hbXotc2VjdXJpdHktdG9rZW4sIFNpZ25hdHVyZT04MzE4EXAMPLEiY2MxZmUzZWU2OWY3NWNkEXAMPLE0Y2I0ZjE1MGU0Zjk5Y2VjODY5ZjE0OWM1ZDAzNDEXAMPLEn0=&payload=e30=
```

**注意**  
一個 WebSocket 連線可以有多個訂閱 （即使使用不同的身分驗證模式）。其中一種實作方式是為第一個訂閱建立 WebSocket 連線，然後在最後一個訂閱取消註冊時將其關閉。您可以等待幾秒鐘再關閉 WebSocket 連線來最佳化此作業，以防應用程式在最後一個訂閱取消註冊後立即訂閱。對於行動應用程式範例，從一個畫面變更為另一個畫面時，*在卸載*事件時，會停止訂閱，而在*掛載*事件時，則會啟動不同的訂閱。

### Lambda 授權
<a name="lambda-auth"></a>

#### Lambda 授權標頭
<a name="lambda-auth-list"></a>

**標頭內容**
+  `"Authorization": <string>`：以 傳遞的值`authorizationToken`。
+  `"host": <string>`： AWS AppSync GraphQL 端點的主機或您的自訂網域名稱。

**範例**

```
{
    "Authorization":"M0UzQzM1MkQtMkI0Ni00OTZCLUI1NkQtMUM0MTQ0QjVBRTczCkI1REEzRTIxLTk5NzItNDJENi1BQjMwLTFCNjRFNzQ2NzlCNQo=",
    "host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
}
```

**透過查詢字串的標頭**

首先，包含 `host`和 的 JSON 物件`Authorization`會轉換為字串。接下來，此字串會使用 base64 編碼進行編碼。產生的 base64 編碼字串會新增為名為 WebSocket URL `header`的查詢參數，以建立與 AWS AppSync 即時端點的連線。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

請務必注意，除了 base64 編碼的標頭物件之外，空的 JSON 物件 \$1\$1 也是 base64 編碼的，並包含在 WebSocket URL `payload`中做為名為 的個別查詢參數。

**透過 的標頭 `Sec-WebSocket-Protocol`**

包含 `host`和 的 JSON 物件`Authorization`會轉換為字串，然後使用 base64Url 編碼進行編碼。產生的 base64Url-encoded字串字首為 `header-`。在與 AWS AppSync 即時端點建立 WebSocket 連線時，除了 `Sec-WebSocket-Protocol`標頭`graphql-ws`中的 之外，此字首字串也會用作新的子通訊協定。

產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 標頭包含下列值：

```
"sec-websocket-protocol" : ["graphql-ws", "header-ewogICAgImhvc3QiOiJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsCiAgICAieC1hcGkta2V5IjoiZGEyLTEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Igp9"]
```

**透過標準 HTTP 標頭的標頭**

在此方法中，在與 AWS AppSync 即時端點建立 WebSocket 連線時，會使用標準 HTTP 標頭傳輸主機和授權資訊。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

請求標頭會包含下列項目：

```
"sec-websocket-protocol" : ["graphql-ws"]
"Authorization":"eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJHWEFLSXBieU5WNHhsQjEXAMPLEnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyEXAMPLEiJhNmNmMjcwNy0xNjgxLTQ1NDItOWYxOC1lNjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImVkMzM5MmNkLWNjYTMtNGM2OC1hNDYyLTJlZGI3ZTNmY2FjZiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk0NTc3MTgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zb3V0aGVhc3QtMl83OHY0SVZibVAiLCJleHAiOjE1Njk0NjEzMjAsImlhdCI6MTU2OTQ1NzcyMCwianRpIjoiNTgzZjhmYmMtMzk2MS00YzA4LWJhZTAtYzQyY2IxMTM5NDY5IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1N3RoZWw0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3EXAMPLEn0.B4EXAMPLEFNpJ6ikVp7e6DRee95V6Qi-zEE2DJH7sHOl2zxYi7f-SmEGoh2AD8emxQRYajByz-rE4Jh0QOymN2Ys-ZIkMpVBTPgu-TMWDyOHhDUmUj2OP82yeZ3wlZAtr_gM4LzjXUXmI_K2yGjuXfXTaa1mvQEBG0mQfVd7SfwXB-jcv4RYVi6j25qgow9Ew52ufurPqaK-3WAKG32KpV8J4-Wejq8t0c-yA7sb8EnB551b7TU93uKRiVVK3E55Nk5ADPoam_WYE45i3s5qVAP_-InW75NUoOCGTsS8YWMfb6ecHYJ-1j-bzA27zaT9VjctXn9byNFZmEXAMPLExw",
"host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
```

## 即時 WebSocket 操作
<a name="real-time-websocket-operation"></a>

使用 AWS AppSync 啟動成功的 WebSocket 交握後，用戶端必須傳送後續訊息，以連線至不同操作的 AWS AppSync。這些訊息需要下列資料：
+  `type`：操作類型。
+  `id`：訂閱的唯一識別符。我們建議您使用 UUID 來達到此目的。
+  `payload`：相關聯的承載，取決於操作類型。

`type` 欄位是唯一的必要欄位； `id`和 `payload` 欄位是選用的。

### 事件順序
<a name="sequence-of-events"></a>

若要成功啟動、建立、註冊和處理訂閱請求，用戶端必須逐步執行下列順序：

1. 初始化連線 (`connection_init`)

1. 連線確認 (`connection_ack`)

1. 訂閱註冊 (`start`)

1. 訂閱確認 (`start_ack`)

1. 正在處理訂閱 (`data`)

1. 取消註冊訂閱 (`stop`)

## 連線初始化訊息
<a name="connection-init-message"></a>

（選用） 成功交握後，用戶端可以傳送訊息`connection_init`，開始與 AWS AppSync 即時端點通訊。訊息是透過將 JSON 物件字串化來取得的字串，如下所示：

```
{ "type": "connection_init" }
```

## 連線確認訊息
<a name="connection-acknowledge-message"></a>

傳送 `connection_init` 訊息後，用戶端必須等待 `connection_ack` 訊息。接收前傳送的所有訊息`connection_ack`都會遭到忽略。該訊息應該如下所示：

```
{
  "type": "connection_ack",
  "payload": {
    // Time in milliseconds waiting for ka message before the client should terminate the WebSocket connection
    "connectionTimeoutMs": 300000
  }
}
```

## 保持啟用訊息
<a name="keep-alive-message"></a>

除了連線確認訊息之外，用戶端還會定期接收保持連線訊息。如果用戶端未在連線逾時期間內收到持續連線訊息，用戶端應關閉連線。 AWS AppSync 會持續傳送這些訊息和服務已註冊的訂閱，直到其自動關閉連線為止 (24 小時後）。保持連線訊息是活動訊號，不需要用戶端來確認它們。

```
{ "type": "ka" }
```

## 訂閱註冊訊息
<a name="subscription-registration-message"></a>

用戶端收到`connection_ack`訊息後，用戶端可以將訂閱註冊訊息傳送至 AWS AppSync。此類型的訊息是字串化的 JSON 物件，其中包含下列欄位：
+  `"id": <string>`：訂閱的 ID。此 ID 對於每個訂閱都必須是唯一的，否則伺服器會傳回錯誤，指出訂閱 ID 重複。
+  `"type": "start"`：常數 `<string>` 參數。
+  `"payload": <Object>`：包含訂閱相關資訊的物件。
  +  `"data": <string>`：包含 GraphQL 查詢和變數的字串化 JSON 物件。
    +  `"query": <string>`：GraphQL 操作。
    +  `"variables": <Object>`：包含查詢變數的物件。
  +  `"extensions": <Object>`：包含授權物件的物件。
+  `"authorization": <Object>`：包含授權所需欄位的物件。

### 訂閱註冊的授權物件
<a name="authorization-object-for-subscription-registration"></a>

[以 AWS AppSync API 授權模式為基礎的標頭參數格式](#header-parameter-format-based-on-appsync-api-authorization-mode) 區段中的相同規則適用於授權物件。唯一的例外是 IAM，其中 SigV4 簽章資訊略有不同。如需詳細資訊，請參閱 IAM 範例。

使用 Amazon Cognito 使用者集區的範例：

```
{
  "id": "ee849ef0-cf23-4cb8-9fcb-152ae4fd1e69",
  "payload": {
    "data": "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
      "extensions": {
        "authorization": {
          "Authorization": "eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJEXAMPLEBieU5WNHhsQjhPVW9YMnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyJzdWIiOiJhNmNmMjcwNy0xNjgxLTQ1NDItEXAMPLENjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImU3YWVmMzEyLWUEXAMPLEY0Zi04YjlhLTRjMWY5M2Q5ZTQ2OCIsInRva2VuX3VzZSI6ImFjY2VzcyIsIEXAMPLEIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk2MTgzMzgsImlzcyI6Imh0dEXAMPLEXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zbEXAMPLEc3QtMl83OHY0SVZibVAiLCJleHAiOjE1NzAyNTQ3NTUsImlhdCI6MTU3MDI1MTE1NSwianRpIjoiMmIEXAMPLEktZTVkMi00ZDhkLWJiYjItNjA0YWI4MDEwOTg3IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1EXAMPLE0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3J6YWZlIn0.CT-qTCtrYeboUJ4luRSTPXaNewNeEXAMPLE14C6sfg05tO0fOMpiUwj9k19gtNCCMqoSsjtQoUweFnH4JYa5EXAMPLEVxOyQEQ4G7jQrt5Ks6STn53vuseR3zRW9snWgwz7t3ZmQU-RWvW7yQU3sNQRLEXAMPLEcd0yufBiCYs3dfQxTTdvR1B6Wz6CD78lfNeKqfzzUn2beMoup2h6EXAMPLE4ow8cUPUPvG0DzRtHNMbWskjPanu7OuoZ8iFO_Eot9kTtAlVKYoNbWkZhkD8dxutyoU4RSH5JoLAnrGF5c8iKgv0B2dfEXAMPLEIihxaZVJ9w9w48S4EXAMPLEcA",
          "host": "example1234567890000.appsync-api.us-east-1.amazonaws.com"
         }
      }
  },
  "type": "start"
}
```

使用 IAM 的範例：

```
{
  "id": "eEXAMPLE-cf23-1234-5678-152EXAMPLE69",
  "payload": {
    "data": "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
    "extensions": {
      "authorization": {
        "accept": "application/json, text/javascript",
        "content-type": "application/json; charset=UTF-8",
        "X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
        "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=b90131a61a7c4318e1c35ead5dbfdeb46339a7585bbdbeceeaff51f4022eb1fd",
        "content-encoding": "amz-1.0",
        "host": "example1234567890000.appsync-api.us-east-1.amazonaws.com",
        "x-amz-date": "20200401T001010Z"
      }
    }
  },
  "type": "start"
}
```

使用自訂網域名稱的範例：

```
{
  "id": "key-cf23-4cb8-9fcb-152ae4fd1e69",
  "payload": {
    "data": "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
      "extensions": {
        "authorization": {
          "x-api-key": "da2-12345678901234567890123456",
          "host": "api.example.com"
         }
      }
  },
  "type": "start"
}
```

SigV4 簽章不需要`/connect`附加至 URL，而且 JSON 字串化 GraphQL 操作會取代 `data`。以下是 SigV4 簽章請求的範例：

```
{
  url: "https://example1234567890000.appsync-api.us-east-1.amazonaws.com/graphql",
  data: "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
  method: "POST",
  headers: {
    "accept": "application/json, text/javascript",
    "content-encoding": "amz-1.0",
    "content-type": "application/json; charset=UTF-8",
  }
}
```

## 訂閱確認訊息
<a name="subscription-acknowledge-message"></a>

傳送訂閱開始訊息後，用戶端應該等待 AWS AppSync 傳送訊息`start_ack`。`start_ack` 訊息指出訂閱成功。

訂閱確認範例：

```
{
  "type": "start_ack",
  "id": "eEXAMPLE-cf23-1234-5678-152EXAMPLE69"
}
```

## 錯誤訊息
<a name="error-message"></a>

如果連線初始化或訂閱註冊失敗，或訂閱從伺服器結束，伺服器會傳送錯誤訊息給用戶端。如果在連線初始化期間發生錯誤，伺服器將會關閉連線。
+  `"type": "error"`：常數 `<string>` 參數。
+  `"id": <string>`：相應已註冊訂閱的 ID，如果相關的話。
+  `"payload" <Object>`：包含對應錯誤資訊的物件。

範例：

```
{
  "type": "error",
  "payload": {
    "errors": [
      {
        "errorType": "LimitExceededError",
        "message": "Rate limit exceeded"
      }
    ]
  }
}
```

## 處理資料訊息
<a name="processing-data-messages"></a>

當用戶端提交變動時， AWS AppSync 會識別對其感興趣的所有訂閱者，並使用訂閱操作中對應的訂閱傳送訊息`"type":"data"`給每個`id``"start"`訂閱者。預期用戶端會追蹤`id`其傳送的訂閱，以便在接收資料訊息時，用戶端可以比對其與對應的訂閱。
+  `"type": "data"`：常數 `<string>` 參數。
+  `"id": <string>`：對應已註冊訂閱的 ID。
+  `"payload" <Object>`：包含訂閱資訊的物件。

範例：

```
{
  "type": "data",
  "id": "ee849ef0-cf23-4cb8-9fcb-152ae4fd1e69",
  "payload": {
    "data": {
      "onCreateMessage": {
        "__typename": "Message",
        "message": "test"
      }
    }
  }
}
```

## 訂閱取消註冊訊息
<a name="subscription-unregistration-message"></a>

當應用程式想要停止監聽訂閱事件時，用戶端應該使用下列字串化 JSON 物件傳送訊息：
+  `"type": "stop"`：常數 `<string>` 參數。
+  `"id": <string>`：要取消註冊的訂閱 ID。

範例：

```
{
  "type":"stop",
  "id":"ee849ef0-cf23-4cb8-9fcb-152ae4fd1e69"
}
```

AWS AppSync 會使用下列字串化 JSON 物件傳回確認訊息：
+  `"type": "complete"`：常數 `<string>` 參數。
+  `"id": <string>`：未註冊訂閱的 ID。

用戶端收到確認訊息後，就不會再收到此特定訂閱的訊息。

範例：

```
{
  "type":"complete",
  "id":"eEXAMPLE-cf23-1234-5678-152EXAMPLE69"
}
```

## 斷開 WebSocket 的連線
<a name="disconnecting-the-websocket"></a>

在中斷連線之前，為了避免資料遺失，用戶端應具有必要的邏輯，以檢查目前沒有透過 WebSocket 連線進行的操作。從 WebSocket 中斷連線之前，所有訂閱都應該取消註冊。