Azure Web PubSub サービスの内部構造

Azure Web PubSub サービスでは、シンプル WebSocket 接続を使用して、メッセージを発行/サブスクライブする簡単な方法が提供されます。

  • クライアントは、Websocket に対応している任意の言語で記述できます。
  • 1 つの接続内でテキスト メッセージとバイナリ メッセージの両方がサポートされています。
  • クライアントがクライアント間でメッセージを直接発行するための単純なプロトコルがあります。
  • サービスによって WebSocket 接続が管理されます。

条件

  • サービス: Azure Web PubSub サービス。
  • 接続: 接続は、クライアントまたはクライアント接続とも呼ばれ、Web PubSub サービスに接続されている個々の WebSocket 接続を表します。 正常に接続されると、一意の接続 ID が Web PubSub サービスによってこの接続に割り当てられます。

  • ハブ: ハブは、一連のクライアント接続の論理的な概念です。 通常は、チャット ハブや通知ハブなど、1 つのシナリオに 1 つのハブを使用します。 クライアント接続の接続時には、1 つのハブに接続し、その有効期間中はそのハブに属します。 クライアント接続がハブに接続すると、ハブが存在します。 異なるアプリケーションでは、異なるハブ名を使用して、1 つの Azure Web PubSub サービスを共有できます。 ハブの数に厳密な制限はありませんが、ハブグループに比べてより多くのサービス負荷を消費します。 動的に生成するのではなく、事前に定義されたハブセットを作成することをお勧めします。

  • グループ: グループはハブへの接続のサブセットです。 必要な場合はいつでも、クライアント接続をグループに追加したり、グループからクライアント接続を削除したりできます。 たとえば、クライアントがチャット ルームに参加したり、クライアントがチャット ルームを離れたりするときに、このチャット ルームをグループと見なすことができます。 クライアントは複数のグループに参加できます。また、1 つのグループに複数のクライアントを含めることもできます。 グループはグループ "セッション" のようなもので、グループセッションは誰かがグループに参加すると作成され、グループに誰もいなくなるとセッションは終了します。 グループに送信されたメッセージは、グループに接続されているすべてのクライアントに配信されます。

  • ユーザー: Web PubSub への接続を 1 人のユーザーに所属させることができます。 1 人のユーザーが複数のデバイスまたは複数のブラウザー タブに接続されている場合など、ユーザーが複数の接続を持つ場合があります。

  • メッセージ: クライアントが接続されている場合は、WebSocket 接続を介して、アップストリーム アプリケーションにメッセージを送信したり、アップストリーム アプリケーションからメッセージを受信したりできます。 メッセージはプレーンテキスト、バイナリ、または JSON 形式で指定でき、最大サイズは 1 MB です。

  • クライアント接続ConnectionId: クライアントは /client エンドポイントに接続します。接続されると、サービスによって一意の connectionId がクライアント接続の一意の ID として生成されます。 その後、ユーザーはこの connectionId を使用してクライアント接続を管理できます。 詳細については、「クライアント プロトコル」セクションを参照してください。

  • クライアント イベント: イベントは、クライアント接続のライフサイクル中に作成されます。 たとえば、シンプル WebSocket クライアント接続では、サービスへの接続が試みられるときに connect イベント、サービスに正常に接続したときに connected イベント、サービスにメッセージを送信するときに message イベント、サービスから切断したときに disconnected イベントが作成されます。 クライアント イベントの詳細については、「クライアント プロトコル」セクションを参照してください。

  • イベント ハンドラー: イベント ハンドラーには、クライアント イベントを処理するロジックが含まれています。 事前にポータルまたは Azure CLI から、サービスにイベント ハンドラーを登録して構成します。 詳細については、「イベント ハンドラー」セクションを参照してください。

  • イベント リスナー (プレビュー): イベント リスナーはクライアント イベントをリッスンするだけであり、応答によってクライアントの有効期間に干渉することはありません。 詳細は「イベント リスナー」セクションにあります。

  • サーバー: サーバーでは、クライアント イベントを処理したり、クライアント接続を管理したり、グループにメッセージを発行したりできます。 イベント ハンドラーもイベント リスナーもサーバー側と見なされます。 サーバーの詳細については、「サーバー プロトコル」セクションを参照してください。

ワークフロー

Diagram showing the Web PubSub service workflow.

上のグラフに示されているワークフロー:

  1. クライアントは、WebSocket トランスポートを使用してサービス /client エンドポイントに接続します。 サービスは、すべての WebSocket フレームを、構成されているアップストリーム (サーバー) に転送します。 WebSocket 接続では、サーバーが処理する任意のカスタム サブプロトコルを使用して接続できます。また、サービスでサポートされているサブプロトコル json.webpubsub.azure.v1 を使用して接続することもでき、これにより、クライアントが pub/sub を直接実行できます。 詳細については、「クライアント プロトコル」を参照してください。
  2. さまざまなクライアント イベントで、サービスは CloudEvents プロトコル を使用してサーバーを呼び出します。 CloudEvents は、Cloud Native Computing Foundation (CNCF) によってホストされるイベントの構造とメタデータ記述の標準化されたプロトコルに依存しない定義です。 「サーバー プロトコル」に記載されているとおり、CloudEvents プロトコルの詳細な実装はサーバー ロールに依存します。
  3. Web PubSub サーバーは、REST API を使用してサービスを呼び出し、クライアントにメッセージを送信したり、接続されているクライアントを管理したりできます。 詳細については、「サーバー プロトコル」を参照してください

クライアント プロトコル

クライアント接続では、WebSocket プロトコルを使用して、サービスの /client エンドポイントに接続します。 WebSocket プロトコルは、単一の TCP 接続で全二重通信チャネルを提供し、2011 年に RFC 6455 として IETF によって標準化されました。 ほとんどの言語に、WebSocket 接続を開始するためのネイティブ サポートがあります。

ここのサービスでは、次の 2 種類のクライアントをサポートします。

シンプル WebSocket クライアント

シンプル WebSocket クライアントとは、その名前が示すように、単純な WebSocket 接続です。 これもそのカスタム サブプロトコルを使用することができます。

たとえば JS では、次のコードを使用してシンプル WebSocket クライアントを作成できます。

// simple WebSocket client1
var client1 = new WebSocket("wss://test.webpubsub.azure.com/client/hubs/hub1");

// simple WebSocket client2 with some custom subprotocol
var client2 = new WebSocket(
  "wss://test.webpubsub.azure.com/client/hubs/hub1",
  "custom.subprotocol"
);

次のシーケンス図に示すように、シンプル WebSocket クライアントはクライアント<->サーバー アーキテクチャに従います。Diagram showing the sequence for a client connection.

  1. クライアントが WebSocket ハンドシェイクを開始すると、サービスは WebSocket ハンドシェイクのための connect イベント ハンドラーの呼び出しを試みます。 開発者は、このハンドラーを使用して WebSocket ハンドシェイクを処理し、使用するサブプロトコルを決定し、クライアントを認証して、クライアントをグループに参加させることができます。
  2. クライアントが正常に接続されると、サービスは connected イベント ハンドラーを呼び出します。 これは通知として機能し、クライアントのメッセージの送信をブロックしません。 開発者は、このハンドラーを使用してデータ ストレージを実行し、クライアントへのメッセージで応答できます。 また、サービスは、すべての関連するイベント リスナー (存在する場合) に connected イベントをプッシュします。
  3. クライアントがメッセージを送信すると、サービスはイベント ハンドラーに対して message イベントをトリガーし、送信されたメッセージを処理します。 このイベントは、WebSocket フレームで送信されるメッセージを含む一般的なイベントです。 コードでは、このイベント ハンドラー内でメッセージをディスパッチする必要があります。 イベント ハンドラーから不成功の応答コードが返される場合、サービスはクライアント接続を切断します。 また、サービスは、すべての関連するイベント リスナー (存在する場合) に message イベントをプッシュします。 サービスは、メッセージを受信するための登録済みサーバーを検出できない場合にも、接続を切断します。
  4. クライアントが切断された場合、サービスは、切断を検出すると、イベント ハンドラーに対して disconnected イベントのトリガーを試みます。 また、サービスは、すべての関連するイベント リスナー (存在する場合) に disconnected イベントをプッシュします。

シナリオ

これらの接続は、クライアントがサーバーにメッセージを送信し、サーバーがイベント ハンドラーを使用して受信メッセージを処理する、一般的なクライアント サーバー アーキテクチャで使用できます。 また、顧客がアプリケーション ロジックで既存のサブプロトコルを適用する場合にも使用できます。

PubSub WebSocket クライアント

このサービスでは、json.webpubsub.azure.v1 と呼ばれる特定のサブプロトコルもサポートされています。これにより、クライアントはアップストリーム サーバーへのラウンド トリップではなく、発行/サブスクライブを直接実行できます。 ここでは、json.webpubsub.azure.v1 サブプロトコルを持つ WebSocket 接続を、PubSub WebSocket クライアントと呼びます。 詳細については、GitHub の「Web PubSub クライアントの仕様」を参照してください。

たとえば JS では、次のコードを使用して PubSub WebSocket クライアントを作成できます。

// PubSub WebSocket client
var pubsub = new WebSocket(
  "wss://test.webpubsub.azure.com/client/hubs/hub1",
  "json.webpubsub.azure.v1"
);

PubSub WebSocket クライアントでは次が可能です。

  • グループに参加する。例:

    {
      "type": "joinGroup",
      "group": "<group_name>"
    }
    
  • グループを脱退する。例:

    {
      "type": "leaveGroup",
      "group": "<group_name>"
    }
    
  • グループにメッセージを発行する。例:

    {
      "type": "sendToGroup",
      "group": "<group_name>",
      "data": { "hello": "world" }
    }
    
  • カスタム イベントをアップストリーム サーバーに送信する。例:

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

PubSub WebSocket サブプロトコルに関するページで、json.webpubsub.azure.v1 サブプロトコルの詳細を説明しています。

シンプル WebSocket クライアントの場合、"サーバー" は、クライアントから message イベントを受信するための must have (必須) ロールであることにお気付きかもしれません。 シンプルな WebSocket 接続では、メッセージを送信するときには必ず message イベントをトリガーします。そして常にサーバー側に依存して、メッセージを処理したり他の操作を行ったりします。 json.webpubsub.azure.v1 サブプロトコルのおかげで、許可されているクライアントはグループに参加し、メッセージをグループに直接発行できます。 また、メッセージが属する "イベント" をカスタマイズすることで、別のイベント ハンドラーやイベント リスナーにメッセージをルーティングすることもできます。

シナリオ

このようなクライアントは、クライアントが相互に通信する必要がある場合に使用できます。 メッセージは client2 からサービスに送信され、クライアントがその権限を持つ場合に、サービスによってメッセージが client1 に直接配信されます。

Client1:

var client1 = new WebSocket(
  "wss://xxx.webpubsub.azure.com/client/hubs/hub1",
  "json.webpubsub.azure.v1"
);
client1.onmessage = (e) => {
  if (e.data) {
    var message = JSON.parse(e.data);
    if (message.type === "message" && message.group === "Group1") {
      // Only print messages from Group1
      console.log(message.data);
    }
  }
};

client1.onopen = (e) => {
  client1.send(
    JSON.stringify({
      type: "joinGroup",
      group: "Group1",
    })
  );
};

Client2:

var client2 = new WebSocket("wss://xxx.webpubsub.azure.com/client/hubs/hub1", "json.webpubsub.azure.v1");
client2.onopen = e => {
    client2.send(JSON.stringify({
        type: "sendToGroup",
        group: "Group1",
        data: "Hello Client1"
    });
};

上の例に示すように、client1 が含まれる Group1 にメッセージを発行することで、client2 はデータを client1 に直接送信します。

クライアント イベントの概要

クライアント イベントは以下の 2 つのカテゴリに分けられます。

  • 同期イベント (ブロッキング): 同期イベントにより、クライアント ワークフローがブロックされます。
    • connect: このイベントはイベント ハンドラー専用です。 クライアントが WebSocket ハンドシェイクを開始すると、イベントがトリガーされ、開発者は connect イベント ハンドラーを使用して WebSocket ハンドシェイクを処理し、使用するサブプロトコルを決定し、クライアントを認証して、クライアントをグループに参加させることができます。
    • message: このイベントは、クライアントがメッセージを送信するときにトリガーされます。
  • 非同期イベント (非ブロッキング): 非同期イベントは、クライアント ワークフローをブロックせず、サーバーへの何らかの通知として機能します。 このようなイベント トリガーが失敗すると、サービスによってエラーの詳細がログに記録されます。
    • connected: このイベントは、クライアントがサービスに正常に接続されたときにトリガーされます。
    • disconnected: このイベントは、クライアントがサービスから切断されたときにトリガーされます。

クライアント メッセージの制限

1 つの WebSocket フレームで許可される最大メッセージ サイズは 1 MB です。

クライアント認証

認証ワークフロー

クライアントは、署名された JWT トークンを使用してサービスに接続します。 アップストリームでは、それが受信クライアントの connect イベント ハンドラーである場合に、クライアントを拒否できます。 イベント ハンドラーでは、クライアントが持つ userIdrole を Webhook 応答に指定することで、クライアントを認証するか、または 401 でクライアントを拒否します。 「イベント ハンドラー」セクションで、これについて詳しく説明します。

次のグラフは、ワークフローを示しています。

Diagram showing the client authentication workflow.

PubSub WebSocket クライアントについて説明したときにお気付きかもしれませんが、クライアントは "許可されている" 場合にのみ、他のクライアントに発行できます。 クライアントの role により、クライアントが持つ "最初" のアクセス許可が決まります。

役割 アクセス許可
指定なし クライアントはイベントを送信できます。
webpubsub.joinLeaveGroup クライアントは、どのグループについても、参加と脱退が可能です。
webpubsub.sendToGroup クライアントは、どのグループにもメッセージを発行できます。
webpubsub.joinLeaveGroup.<group> クライアントはグループ <group> について、参加と脱退が可能です。
webpubsub.sendToGroup.<group> クライアントはグループ <group> にメッセージを発行できます。

後のセクションで示されているとおりに、サーバー側では、サーバー プロトコルによって、クライアントのアクセス許可を動的に許可または取り消すこともできます。

サーバー プロトコル

サーバー プロトコルは、サーバーがクライアント イベントを処理し、クライアント接続とグループを管理するための機能を提供します。

一般に、サーバー プロトコルには以下の 3 つのロールがあります。

  1. イベント ハンドラー
  2. Connection manager
  3. イベント リスナー

イベント ハンドラー

イベント ハンドラーでは、受信クライアント イベントが処理されます。 イベント ハンドラーは、ポータルまたは Azure CLI を使用してサービスに登録し設定されます。 クライアント イベントがトリガーされると、サービスはイベントを処理する必要があるかどうかを識別できます。 次に、PUSH モードを使用してイベント ハンドラーを呼び出します。 サーバー側のイベント ハンドラーにより、イベントがトリガーされたときに呼び出すサービスのパブリックにアクセス可能なエンドポイントが公開されます。 それは、Webhook として機能します。

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

すべてのイベントに対して、このサービスは登録されたアップストリームへの HTTP POST 要求を形成し、HTTP 応答を期待します。

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

Diagram showing the Web PubSub service event push mode.

アップストリームと検証

イベント ハンドラーは、最初に使用する前に、ポータルまたは Azure CLI を使用してサービスに登録し設定しておく必要があります。 クライアント イベントがトリガーされると、サービスはイベントを処理する必要があるかどうかを識別できます。 パブリック プレビューでは、PUSH モードを使用してイベント ハンドラーを呼び出します。 サーバー側のイベント ハンドラーにより、イベントがトリガーされたときに呼び出すサービスのパブリックにアクセス可能なエンドポイントが公開されます。 それは、Webhook アップストリームとして機能します。

URL は、{event} パラメーターを使用して Webhook ハンドラーの URL テンプレートを定義できます。 サービスでは、クライアント要求を受信すると、Webhook URL の値が動的に計算されます。 たとえば、ハブ /client/hubs/chat にイベント ハンドラー URL パターン http://host.com/api/{event} が構成されている状態で、要求 chat を受信すると、クライアントは接続するときに、最初に URL http://host.com/api/connect に POST します。 この動作は、PubSub WebSocket クライアントがカスタム イベントを送信するときに役立つ可能性があり、イベント ハンドラーでは、さまざまなイベントをさまざまなアップストリームにディスパッチできます。 URL ドメイン名では {event} パラメーターを使用できません。

Azure portal または CLI を使用して、アップストリームにイベントハンドラーを設定すると、サービスによって CloudEvents の不正使用防止に従ってアップストリームの Webhook が検証されます。 WebHook-Request-Origin 要求ヘッダーはサービス ドメイン名 xxx.webpubsub.azure.com に設定されており、これは応答にこのドメイン名を含むヘッダー WebHook-Allowed-Origin があることが期待されます。

検証を実行すると、{event} パラメーターは validate に解決されます。 たとえば、URL を http://host.com/api/{event} に設定しようとすると、サービスによって、http://host.com/api/validate に対する要求の OPTIONS が試みられ、応答が有効な場合にのみ、構成を正常に設定できます。

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

サービスと Webhook 間の認証/認可

  • 匿名モード
  • 構成済みの Webhook URL を介して code が提供される簡易認証。
  • Microsoft Entra 認可を使用します。 詳細については、マネージド ID の使用方法に関する記事を参照してください。
    • 手順 1: Web PubSub サービスの ID を有効にする
    • 手順 2: Webhook Web アプリを表す既存の Microsoft Entra アプリケーションから選ぶ

[ODBC 入力元エディター]

サーバーは本質的に許可されているユーザーです。 イベント ハンドラー ロールのおかげで、サーバーはクライアントのメタデータ (connectionIduserId など) を認識できるため、次のことが可能になります。

  • クライアント接続を閉じる
  • メッセージをクライアントに送信する
  • 同じユーザーに属するクライアントにメッセージを送信する
  • クライアントをグループに追加する
  • 同じユーザーとして認証されたクライアントをグループに追加する
  • クライアントをグループから削除する
  • 同じユーザーとして認証されたクライアントをグループから削除する
  • グループにメッセージを発行する

また、PubSub クライアントの発行/参加アクセス許可を許可または取り消すこともできます。

  • 特定のグループまたはすべてのグループに発行/参加アクセス許可を許可する
  • 特定のグループまたはすべてのグループの発行/参加アクセス許可を取り消す
  • クライアントに、特定のグループまたはすべてのグループへの参加/発行アクセス許可があるかどうかを確認する

サービスによって、サーバーが接続管理を行うための REST API が提供されます。

Diagram showing the Web PubSub service connection manager workflow.

詳細な REST API プロトコルはこちらに定義されています。

イベント リスナー

Note

イベント リスナー機能はプレビュー段階です。

イベント リスナーは、受信クライアント イベントをリッスンします。 各イベント リスナーには、関連するイベントの種類を指定するフィルターと、イベントの送信先に関するエンドポイントが含まれています。

現在、イベント リスナー エンドポイントとして Event Hubs がサポートされています。

クライアント イベントがトリガーされたときに、サービスが対応するイベント リスナーにイベントをプッシュできるように、イベント リスナーを事前に登録しておく必要があります。 イベント ハブ エンドポイントを使用してイベント リスナーを構成する方法については、こちらのドキュメントを参照してください。

複数のイベント リスナーを構成できます。 イベント リスナーの順序は関係ありません。 イベントが複数のイベント リスナーと一致する場合は、一致するすべてのリスナーに送信されます。 次の図の例を参照してください。 4 つのイベント リスナーを同時に構成するとします。 そのうちの 3 つのリスナーと一致するクライアント イベントが 3 つのリスナーに送信され、残りの 1 つはそのままになります。

Event listener data flow diagram sample

同じイベントに対して、イベント ハンドラーとイベント リスナーを組み合わて使用することができます。 この場合、イベント ハンドラーとイベント リスナーの両方がイベントを受信します。

Web PubSub サービスは、Azure Web PubSub の CloudEvents AMQP 拡張機能を使用して、イベント リスナーにクライアント イベントを送信します。

まとめ

イベント ハンドラー ロールでは、サービスからサーバーへの通信が処理されますが、マネージャー ロールでは、サーバーからサービスへの通信が処理されることにお気づきかもしれません。 2 つのロールを組み合わせると、サービスとサーバーの間のデータ フローは、HTTP プロトコルを使用した次の図のようになります。

Diagram showing the Web PubSub service bi-directional workflow.

次のステップ

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