Azure Web PubSub イベント ハンドラーの CloudEvents 拡張機能と HTTP プロトコル

Web PubSub サービスは、CloudEvents HTTP プロトコル バインドを使用し、アップストリームの Webhook にクライアント イベントを配信します。

Web PubSub サービスからサーバーに送信されるデータは常に CloudEvents binary 形式です。

Webhook の検証

Webhook の検証は、CloudEvents に従います。 要求のヘッダーには常に WebHook-Request-Origin: xxx.webpubsub.azure.com が含まれます。

配信ターゲットでイベントの配信が許可されている場合にのみ、WebHook-Allowed-Origin ヘッダーを含めることによって要求に応答する必要があります。次に例を示します。

WebHook-Allowed-Origin: *

または:

WebHook-Allowed-Origin: xxx.webpubsub.azure.com

現在、WebHook-Request-RateWebHook-Request-Callback はサポートされていません。

Web PubSub CloudEvents の属性の拡張

また、HTTP 仕様は似たパターンに従うようになっており、拡張 HTTP ヘッダーにプレフィックスとして X- が付いていないことも指摘されました。

この拡張機能では、Web PubSub によって生成されるすべてのイベントに使用される属性が定義されています。

属性

名前 種類 説明設定
userId string 接続が認証されるユーザー
hub string 接続が属しているハブ
connectionId string connectionId はクライアント接続に対して一意です
eventName string プレフィックスのないイベントの名前
subprotocol string クライアントで使用されているサブプロトコル (ある場合)
connectionState string 接続の状態を定義します。 同じ応答ヘッダーを使用して、状態の値をリセットできます。 複数の connectionState ヘッダーは使用できません。 内部に複雑な文字が含まれている場合は、base64 で文字列値をエンコードします。たとえば、この属性を使用して base64(jsonString) で複合オブジェクトを渡します。
signature string 受信要求が予期される配信元からのものであるかどうかを検証するための、アップストリーム Webhook の署名。 サービスによって、プライマリ アクセス キーとセカンダリ アクセス キーの両方を HMAC キーとして使用して、Hex_encoded(HMAC_SHA256(accessKey, connectionId)) のように値が計算されます。 上流では、要求を処理する前に、それが有効かどうかを確認する必要があります。

Events

イベントには 2 種類あります。 1 つは、サービスがイベントの応答を待ってから続行する "ブロック" イベントです。 もう 1 つは、サービスが次のメッセージを処理する前にイベントの応答を待たない "非ブロック" イベントです。

システム connect イベント

  • ce-type: azure.webpubsub.sys.connect
  • Content-Type: application/json

要求の形式:

POST /upstream HTTP/1.1
Host: xxxxxx
WebHook-Request-Origin: xxx.webpubsub.azure.com
Content-Type: application/json; charset=utf-8
Content-Length: nnnn
ce-specversion: 1.0
ce-type: azure.webpubsub.sys.connect
ce-source: /hubs/{hub}/client/{connectionId}
ce-id: {eventId}
ce-time: 2021-01-01T00:00:00Z
ce-signature: sha256={connection-id-hash-primary},sha256={connection-id-hash-secondary}
ce-userId: {userId}
ce-connectionId: {connectionId}
ce-hub: {hub}
ce-eventName: connect

{
    "claims": {},
    "query": {},
    "headers": {},
    "subprotocols": [],
    "clientCertificates": [
        {
            "thumbprint": "<certificate SHA-1 thumbprint>",
            "content": "-----BEGIN CERTIFICATE-----\r\n...\r\n-----END CERTIFICATE-----"
        }
    ]
}

成功応答の形式:

  • ヘッダー ce-connectionState: このヘッダーが存在する場合、この接続の接続状態はヘッダーの値に更新されます。 接続状態を更新できるのは "ブロック" イベントのみです。 次の例では、base64 でエンコードされた JSON 文字列を使用して、接続の複雑な状態を格納します。

  • 状態コード:

    • 204: 成功。コンテンツはありません。
    • 200: 成功。コンテンツは JSON 形式である必要があり、次のプロパティが許可されます。
      • subprotocols

        connect イベントによって、クライアントから上流にサブプロトコルと認証情報が転送されます。 Web PubSub サービスが状態コードを使用して、要求が WebSocket プロトコルにアップグレードされるかどうかを判断します。

        要求に subprotocols プロパティが含まれる場合、サーバーはサポートしている 1 つのサブプロトコルを返す必要があります。 サーバーでどのサブプロトコルも使用する必要がない場合は、応答で subprotocol プロパティを送信しないようにする必要があります。 空のヘッダーを送信することは無効です

      • userId: {auth-ed user ID}

        サービスでは匿名接続が許可されているので、サービスにクライアント接続のユーザー ID を通知するのは connect イベントの役割です。 応答ペイロード userId が存在する場合、サービスによってそこからユーザー ID が読み取られます。 要求のクレームからも、connect イベントの応答ペイロードからも、ユーザー ID を読み取ることができない場合、接続は切断されます。

      • groups: {groups to join}

        このプロパティにより、ユーザーがこの接続を 1 つ以上のグループに追加する便利な方法が提供されます。 これにより、この接続を何らかのグループに追加するために別の呼び出しを行う必要はありません。

      • roles: {roles the client has}

        このプロパティにより、アップストリーム Webhook でクライアントを承認するための方法が提供されます。 PubSub WebSocket クライアントの初期アクセス許可を付与するさまざまなロールがあります。 アクセス許可の詳細については、クライアントのアクセス許可に関する記事を参照してください。

HTTP/1.1 200 OK
ce-connectionState: eyJrZXkiOiJhIn0=

{
    "groups": [],
    "userId": "",
    "roles": [],
    "subprotocol": ""
}

エラー応答の形式:

  • 4xx: エラー。上流からの応答が、クライアント要求への応答として返されます。
HTTP/1.1 401 Unauthorized

システム connected イベント

クライアントによる WebSocket ハンドシェイクが完了し、正常に接続されると、サービスによって上流が呼び出されます。

  • ce-type: azure.webpubsub.sys.connected
  • Content-Type: application/json
  • ce-connectionState: eyJrZXkiOiJhIn0=

要求本文は空の JSON です。

要求の形式:

POST /upstream HTTP/1.1
Host: xxxxxx
WebHook-Request-Origin: xxx.webpubsub.azure.com
Content-Type: application/json; charset=utf-8
Content-Length: nnnn
ce-specversion: 1.0
ce-type: azure.webpubsub.sys.connected
ce-source: /hubs/{hub}/client/{connectionId}
ce-id: {eventId}
ce-time: 2021-01-01T00:00:00Z
ce-signature: sha256={connection-id-hash-primary},sha256={connection-id-hash-secondary}
ce-userId: {userId}
ce-connectionId: {connectionId}
ce-hub: {hub}
ce-eventName: connected
ce-subprotocol: abc
ce-connectionState: eyJrZXkiOiJhIn0=

{}

応答の形式:

2xx: 成功時の応答。

connected は非同期イベントであり、応答の状態コードが成功でない場合、サービスによってログにエラーが記録されます。

HTTP/1.1 200 OK

システム disconnected イベント

connect イベントから 2xx 状態コードが返された場合は、クライアント要求が完了した時点で必ず disconnected イベントがトリガーされます。

  • ce-type: azure.webpubsub.sys.disconnected
  • Content-Type: application/json

要求の形式:

POST /upstream HTTP/1.1
Host: xxxxxx
WebHook-Request-Origin: xxx.webpubsub.azure.com
Content-Type: application/json; charset=utf-8
Content-Length: nnnn
ce-specversion: 1.0
ce-type: azure.webpubsub.sys.disconnected
ce-source: /hubs/{hub}/client/{connectionId}
ce-id: {eventId}
ce-time: 2021-01-01T00:00:00Z
ce-signature: sha256={connection-id-hash-primary},sha256={connection-id-hash-secondary}
ce-userId: {userId}
ce-connectionId: {connectionId}
ce-hub: {hub}
ce-eventName: disconnected
ce-subprotocol: abc
ce-connectionState: eyJrZXkiOiJhIn0=

{
    "reason": "{Reason}"
}

  • reason

    reason では、クライアントが切断された理由が示されています。

応答の形式:

2xx: 成功時の応答。

disconnected は非同期イベントであり、応答の状態コードが成功でない場合、サービスによってログにエラーが記録されます。

HTTP/1.1 200 OK

シンプル WebSocket クライアントに対するユーザー イベント message

すべての WebSocket メッセージ フレームに対し、サービスによって上流のイベント ハンドラーが呼び出されます。

  • ce-type: azure.webpubsub.user.message
  • Content-Type: バイナリ フレームの場合は application/octet-stream。テキスト フレームの場合は text/plain

UserPayload は、クライアントが送信するものです。

要求の形式:

POST /upstream HTTP/1.1
Host: xxxxxx
WebHook-Request-Origin: xxx.webpubsub.azure.com
Content-Type: application/octet-stream | text/plain | application/json
Content-Length: nnnn
ce-specversion: 1.0
ce-type: azure.webpubsub.user.message
ce-source: /hubs/{hub}/client/{connectionId}
ce-id: {eventId}
ce-time: 2021-01-01T00:00:00Z
ce-signature: sha256={connection-id-hash-primary},sha256={connection-id-hash-secondary}
ce-userId: {userId}
ce-connectionId: {connectionId}
ce-hub: {hub}
ce-eventName: message
ce-connectionState: eyJrZXkiOiJhIn0=

UserPayload

成功応答の形式

  • status code
    • 204: 成功。コンテンツはありません。
    • 200: 成功。UserResponsePayload の形式は、応答の Content-Type によって異なります。
  • Content-Type: バイナリ フレームの場合は application/octet-stream。テキスト フレームの場合は text/plain
  • ヘッダー Content-Type: バイナリ フレームの場合は application/octet-stream。テキスト フレームの場合は text/plain
  • ヘッダー ce-connectionState: このヘッダーが存在する場合、この接続の接続状態はヘッダーの値に更新されます。 接続状態を更新できるのは "ブロック" イベントのみです。 次の例では、base64 でエンコードされた JSON 文字列を使用して、接続の複雑な状態を格納します。

Content-Typeapplication/octet-stream の場合、サービスからクライアントに binary WebSocket フレームを使用して UserResponsePayload が送信されます。 Content-Typetext/plain の場合、サービスからクライアントに text WebSocket フレームを使用して UserResponsePayload が送信されます。

HTTP/1.1 200 OK
Content-Type: application/octet-stream (for binary frame) or text/plain (for text frame)
Content-Length: nnnn
ce-connectionState: eyJrZXkiOiJhIn0=

UserResponsePayload

エラー応答の形式

状態コードが成功でない場合は、エラー応答と見なされます。 message 応答状態コードが成功でない場合、接続は切断されます。

PubSub WebSocket クライアントに対するユーザー カスタム イベント {custom_event}

すべての有効なカスタム イベント メッセージについて、サービスによりイベント ハンドラー Webhook が呼び出されます。

ケース 1: テキスト データを含むイベントを送信する:

{
    "type": "event",
    "event": "<event_name>",
    "dataType" : "text",
    "data": "text data"
}

上流のイベント ハンドラーでは以下のような内容が受信され、dataType=text の場合、CloudEvents HTTP 要求の Content-Typetext/plain です

POST /upstream HTTP/1.1
Host: xxxxxx
WebHook-Request-Origin: xxx.webpubsub.azure.com
Content-Type: text/plain
Content-Length: nnnn
ce-specversion: 1.0
ce-type: azure.webpubsub.user.<event_name>
ce-source: /client/{connectionId}
ce-id: {eventId}
ce-time: 2021-01-01T00:00:00Z
ce-signature: sha256={connection-id-hash-primary},sha256={connection-id-hash-secondary}
ce-userId: {userId}
ce-connectionId: {connectionId}
ce-hub: {hub_name}
ce-eventName: <event_name>
ce-subprotocol: json.webpubsub.azure.v1
ce-connectionState: eyJrZXkiOiJhIn0=

text data

ケース 2: JSON データを含むイベントを送信する:

{
    "type": "event",
    "event": "<event_name>",
    "dataType" : "json",
    "data": {
        "hello": "world"
    },
}

上流のイベント ハンドラーでは以下のような内容が受信され、dataType=json の場合、CloudEvents HTTP 要求の Content-Typeapplication/json です

POST /upstream HTTP/1.1
Host: xxxxxx
WebHook-Request-Origin: xxx.webpubsub.azure.com
Content-Type: application/json
Content-Length: nnnn
ce-specversion: 1.0
ce-type: azure.webpubsub.user.<event_name>
ce-source: /client/{connectionId}
ce-id: {eventId}
ce-time: 2021-01-01T00:00:00Z
ce-signature: sha256={connection-id-hash-primary},sha256={connection-id-hash-secondary}
ce-userId: {userId}
ce-connectionId: {connectionId}
ce-hub: {hub_name}
ce-eventName: <event_name>
ce-subprotocol: json.webpubsub.azure.v1
ce-connectionState: eyJrZXkiOiJhIn0=

{
    "hello": "world"
}

ケース 3: バイナリ データでイベントを送信する:

{
    "type": "event",
    "event": "<event_name>",
    "dataType" : "binary",
    "data": "aGVsbG8gd29ybGQ=" // base64 encoded binary
}

上流のイベント ハンドラーでは以下のような内容が受信され、dataType=binary の場合、CloudEvents HTTP 要求の Content-Typeapplication/octet-stream です

POST /upstream HTTP/1.1
Host: xxxxxx
WebHook-Request-Origin: xxx.webpubsub.azure.com
Content-Type: application/octet-stream
Content-Length: nnnn
ce-specversion: 1.0
ce-type: azure.webpubsub.user.<event_name>
ce-source: /client/{connectionId}
ce-id: {eventId}
ce-time: 2021-01-01T00:00:00Z
ce-signature: sha256={connection-id-hash-primary},sha256={connection-id-hash-secondary}
ce-userId: {userId}
ce-connectionId: {connectionId}
ce-hub: {hub_name}
ce-eventName: <event_name>
ce-subprotocol: json.webpubsub.azure.v1

<binary data>

成功応答の形式

HTTP/1.1 200 OK
Content-Type: application/octet-stream | text/plain | application/json
Content-Length: nnnn

UserResponsePayload
  • status code
    • 204: 成功。コンテンツはありません。
    • 200: 成功。PubSub WebSocket クライアントに送信されるデータは、Content-Type に依存します。
  • ヘッダー ce-connectionState: このヘッダーが存在する場合、この接続の接続状態はヘッダーの値に更新されます。 接続状態を更新できるのは "ブロック" イベントのみです。 次の例では、base64 でエンコードされた JSON 文字列を使用して、接続の複雑な状態を格納します。
  • ヘッダー Content-Typeapplication/octet-stream の場合、サービスからクライアントに binary として dataType を使用して UserResponsePayload が返送されます。ペイロードは base64 でエンコードされています。 応答のサンプル:
    {
        "type": "message",
        "from": "server",
        "dataType": "binary",
        "data" : "aGVsbG8gd29ybGQ="
    }
    
  • Content-Typetext/plain の場合、サービスからクライアントに dataType として text を使用して UserResponsePayload が送信されます。ペイロードは文字列です。
  • Content-Typeapplication/json の場合、サービスからクライアントに dataType=json を使用して UserResponsePayload が送信されます。応答のペイロードの本文は data 値トークンです。

エラー応答の形式

状態コードが成功でない場合は、エラー応答と見なされます。 {custom_event} 応答状態コードが成功でない場合、接続は切断されます。

次のステップ

これらのリソースを使用して、独自のアプリケーションの構築を開始します。