构建实时 WebSocket 客户端 - AWS AppSync
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

构建实时 WebSocket 客户端

GraphQL 订阅的 AWS AppSync 实时 WebSocket 客户端实施指南

以下顺序图和步骤显示了 WebSocket 客户端、HTTP 客户端以及 AWS AppSync 服务之间的实时订阅工作流。

  1. 客户端建立与 AWS AppSync 实时终端节点的 WebSocket 连接。如果存在网络错误,则客户端应该执行抖动指数退避。有关更多信息,请参阅 AWS 架构博客上的指数退避和抖动

  2. 成功建立 WebSocket 连接后,客户端会发送一 connection_init 条消息。

  3. 客户端等待来自 AWS AppSync 的 connection_ack 消息。此消息包含一个 connectiontTimeoutMs 参数,这是消息 "ka"(即,保持活动状态)的最长等待时间,以毫秒为单位。

  4. AWS AppSync 定期发送保持活动消息 "ka"。客户端跟踪收到每条 "ka" 消息的时间。如果在 connectionTimeoutMs 毫秒内未收到 "ka" 消息,则客户端应终止连接。

  5. 客户端通过发送 start 订阅消息来注册订阅。单个 WebSocket 连接可以支持多个订阅,即使它们处于不同的授权模式。

  6. 客户端等待 AWS AppSync 发送 start_ack 消息来确认订阅成功。如果出现错误,则 AWS AppSync 返回一条 "type": "error" 消息。

  7. 客户端侦听订阅事件。这些是在调用对应的更改之后发送的。查询和更改通常通过 https:// 发送到 AWS AppSync GraphQL 终端节点。订阅使用安全 WebSocket (wss://) 流经 AWS AppSync 实时终端节点。

  8. 客户端通过发送 stop 订阅消息来取消注册订阅。

  9. 取消注册所有订阅并检查没有通过 WebSocket 传输的消息后,客户端可以从 WebSocket 连接断开。

建立 WebSocket 连接的握手详细信息

要使用 AWS AppSync 进行连接并启动成功的握手,WebSocket 客户端需要以下信息:

  • AppSync 实施终端节点

  • 包含以下参数的查询字符串:headerpayload

    • header:包含与 AWS AppSync 终端节点和授权相关的信息。这是一个从字符串化的 JSON 对象编码的 base64 字符串。JSON 对象内容因授权模式而异。

    • payloadpayload 的 Base64 编码字符串。

使用这些必需的详细信息,WebSocket 客户端可以连接到 URL,该 URL 包含带有查询字符串的 API 实时终端节点,将 graphql-ws 用作 WebSocket 协议。

从 AWS AppSync GraphQL 终端节点发现 AWS AppSync 实时终端节点

AWS AppSync GraphQL 终端节点和 AWS AppSync 实时终端节点在协议和域方面略有不同。您可以使用 AWS CLI 命令 aws appsync get-graphql-api 检索 AWS AppSync GraphQL 终端节点。

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://) 进行订阅。

基于 AWS AppSync API 授权模式的标头参数格式

连接查询字符串中使用的 header 对象的格式因 AWS AppSync API 授权模式而异。对象中的 host 字段引用 AWS AppSync GraphQL 终端节点,该终端节点用于验证连接,即使 wss:// 调用针对的是实时终端节点。要启动握手并建立授权连接,payload 应为空 JSON 对象。

API 键

标头内容:

  • "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" }

负载内容:

{}

请求 URL:

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

Amazon Cognito 用户池和 OpenID Connect (OIDC)

标头内容:

  • "Authorization": <string>:JWT 访问令牌。

  • "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" }

负载内容:

{}

请求 URL:

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

IAM

标头内容如下:

  • "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 是一个有效的时间戳。请勿在时间戳中包含毫秒。有关更多信息,请参阅 AWS 常规参考 中的处理签名版本 4 中的日期

    • "X-Amz-Security-Token": <string>:AWS 会话令牌,使用临时安全证书时必需。有关更多信息,请参阅 (|IAMlong| 用户指南中)。- "Authorization": <string>:AWS AppSync 终端节点的 SigV4 签名信息。有关签名过程的更多信息,请参阅 AWS 常规参考 中的任务 4:将签名添加到 HTTP 请求

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" }

负载内容:

{}

请求 URL:

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

注意:一个 WebSocket 连接可以有多个订阅(即使使用不同的身份验证模式)。实施这一点的一种方法是,为第一个订阅创建 WebSocket 连接,并在取消注册最后一个订阅时关闭它。这可以通过等待几秒钟再关闭 WebSocket 连接进行优化,以避免在取消注册最后一个订阅之后立即订阅应用程序。对于移动应用程序示例,在从一个屏幕更改到另一个屏幕时,在卸载 事件时,它会停止订阅,而在挂载 事件时,将启动另一个订阅。

实时 WebSocket 操作

使用成功 AWS AppSync 启动 WebSocket 握手后,客户端需要发送后续消息才能完成与 AWS AppSync 进行连接的步骤,用于执行不同操作。这些消息需要以下数据:

  • type:操作的类型。

  • id:订阅的唯一标识符。我们建议为此目的使用 UUID。

  • payload:关联的负载取决于操作类型。

type 字段是唯一的必填字段,idpayload 可选。

事件序列

要成功启动、建立、注册和处理订阅请求,客户端必须逐步完成以下序列:

  1. 初始化连接 (connection_init)

  2. 连接确认 (connection_ack)

  3. 订阅注册 (start)

  4. 订阅确认 (start_ack)

  5. 处理订阅 (data)

  6. 订阅取消注册 (stop)

连接启动消息

成功握手后,客户端必须发送 connection_init 消息以启动与 AWS AppSync 实时终端节点的通信。如果没有此步骤,将忽略所有其他消息。该消息是通过将下列 JSON 对象字符串化获得的字符串,如下所示:

{ "type": "connection_init" }

连接确认消息

发送 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 "connectionTimeout": 300000 } }

保持活动消息

除了连接确认消息外,客户端还会定期接收保持活动消息。如果在连接超时期间未收到保持活动消息,则客户端应终止连接。AWS AppSync 将继续发送这些消息并为注册的订阅提供服务,直到连接自动关闭(24 小时后)。保持活动状态消息是检测信号,无需由客户端确认。

{ "type": "ka" }

订阅注册消息

客户端收到 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>:此项包含授权所需的字段。

订阅注册的授权对象

在 部分中的相同规则适用于授权对象。唯一的例外是 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" }

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", } }

订阅确认消息

发送订阅开始消息后,客户端应等待 AWS AppSync 发送 start_ack 消息。start_ack 指示订阅成功。该消息是以下字符串:

订阅成功示例:

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

错误消息

如果连接启动或订阅注册失败,或者从服务器终止订阅,服务器将向客户端发送以下错误消息:

  • "type": "error":常量 <string> 参数。

  • "id": <string>:对应已注册订阅的 id(如果相关)。

  • "payload" <Object>:此对象包含对应的错误信息。

例如:

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

处理数据消息

当客户端提交更改时,AWS AppSync 标识与此更改相关的所有订阅者,并使用在订阅操作 "start" 中使用的对应订阅 id,向每个订阅者发送 "type":"data" 消息。客户端应跟踪它发送的订阅 id,这样在收到数据消息时,客户端可以将其与对应的订阅匹配。

  • "type": "data":常量 <string> 参数。

  • "id": <string>:对应已注册订阅的 id

  • "payload" <Object>:此对象包含具有订阅信息的数据对象。

例如:

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

订阅取消注册消息

当应用程序希望停止侦听订阅事件时,客户端应该发送带有以下字符串化 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 连接

在断开连接之前,客户端应具有必要的逻辑,检查当前没有通过 WebSocket 连接执行任何操作,以避免数据丢失。在断开与 WebSocket 的连接之前,应先取消注册所有订阅。