Azure Relay ハイブリッド接続プロトコル

Azure Relay は、Azure Service Bus プラットフォームの柱となる重要な機能の 1 つです。 Relay の新しい ハイブリッド接続 は、HTTP と WebSocket をベースにして進化を遂げた、安全でオープンなプロトコルです。 従来の BizTalk Services には、独自技術のプロトコル基盤をベースに構築された同じ名前の機能がありますが、その機能の後継となります。 Azure App Services に統合されたハイブリッド接続は、引き続き現状のままご利用いただけます。

ハイブリッド接続を使用すると、ネットワークで結ばれた 2 つのアプリケーション間で、双方向 (要求-応答) のバイナリ ストリーム通信と簡単なデータグラム フローを実現できます。 一方または両方のパーティが、NAT やファイアウォールの背後に存在していてもかまいません。

この記事では、リスナーのクライアントとセンダーのロールを接続するためのハイブリッド接続リレーでのクライアント側の対話について説明します。 リスナーが新しい接続と要求を受け入れる方法についても説明します。

対話モデル

ハイブリッド接続リレーは、通信に関係する二者がそれぞれのネットワークの範囲から検出して接続できる待ち合わせ場所 (ランデブー ポイント) を Azure クラウド内に設けることによって両者を接続します。 本記事を含む各種ドキュメントや API、Azure Portal でそのランデブー ポイントを "ハイブリッド接続" と呼んでいます。 この記事ではこれ以降、ハイブリッド接続のサービス エンドポイントを "サービス" と呼ぶことにします。

サービスは、Web ソケット接続および HTTP(S) の要求と応答をリレーできます。

この対話モデルには、他の多くのネットワーク API で確立されてきた用語体系が使用されています。 まず受信接続を処理する準備ができたことを示し、その後、受信した接続を受け入れるリスナーがあります。 反対側では、クライアントがリスナーに接続し、接続が受け入れられて双方向の通信経路が確立されることを期待します。 "接続"、"リッスン"、"受け入れ" という言葉は、ほとんどのソケット API で使用されています。

リレー通信モデルでは、どちらの当事者もサービス エンドポイントに対して送信接続を作成します。 その意味では "リスナー" も "クライアント" です。普通にそのように呼ばれているケースもあれば、特別な用語が使用されるケースもあります。 そこでハイブリッド接続に関して、ここでは厳密に次の言葉を使うことにします。

接続の両側に存在するプログラムは、サービスに対するクライアントであることから、"クライアント" と呼ばれます。 接続を待機して受け入れるクライアントは "リスナー" です。"リスナー ロール" のクライアントという表現を使用することもあります。サービスを介してリスナーに対する新しい接続を開始するクライアントは、"センダー" または "センダー ロール" のクライアントと呼びます。

リスナー側の対話

リスナーとサービスとの間には 5 つの対話通信が存在します。具体的な通信の内容については、後述のリファレンス セクションで詳しく説明します。

リッスン、受け入れ、要求メッセージは、サービスから受信されます。 更新および ping 操作は、リスナーによって送信されます。

リッスン メッセージ

リスナーは、接続を受け入れる準備が整っていることをサービスに対して表明するために、送信 WebSocket 接続を作成します。 Relay 名前空間内に構成されているハイブリッド接続の名前や、それに対する "リッスン" 権限を付与するセキュリティ トークンは、接続ハンドシェイクで伝達されます。

この WebSocket がサービスによって許可されると、登録が完了し、確立された WebSocket が "コントロール チャネル" として待機状態になり、以後すべての対話処理が可能となります。 このサービスでは、1 つのハイブリッド接続に対して最大 25 の同時リスナーが許可されます。 AppHooks のクォータはまだ決まっていません。

ハイブリッド接続では、アクティブなリスナーが複数存在する場合、それらのリスナー間で受信接続が負荷分散されます。使用されるリスナーの順序は無作為に決まり、均等な負荷分散がベスト エフォートで試みられます。

受け入れメッセージ

センダーがサービスに対して新しい接続を開くと、サービスは、ハイブリッド接続上のいずれかのアクティブなリスナーを選んで通知を送ります。 この通知は、開いているコントロール チャネルを介し、JSON メッセージとしてリスナーに送信されます。 メッセージには、接続を受け入れる場合にリスナーが接続すべき WebSocket エンドポイントの URL が格納されます。

この URL は、特別な処理を施さずに直接リスナーが使用できます。つまり、リスナーはその URL をそのまま使用する必要があります。 エンコードされた情報の有効期間は限られています。基本的には、エンド ツー エンドで接続が確立されるまでにセンダー側で許容される待機時間に依存します。 上限は 30 秒です。 この URL を使って接続を確立できるのは 1 回のみです。 ランデブー URL との間で WebSocket 接続が確立されると、以後センダーとの間でやり取りされるすべてのアクティビティがその WebSocket で中継されます。 この動作は、サービスによる介入や中間処理なしで行われます。

要求メッセージ

WebSocket 接続だけでなく、ハイブリッド接続で機能が明示的に有効になっている場合は、リスナーはセンダーから HTTP 要求フレームを受信することもできます。

HTTP サポートを使用してハイブリッド接続に接続するリスナーは、request ジェスチャを処理する必要があります。 request を処理せず、したがって接続中にタイムアウト エラーを繰り返すリスナーは、将来的にサービスによってブロックされることがあります。

リスナー フレームワークで簡単に処理できるよう、また JSON パーサーより HTTP ヘッダー解析ライブラリの方が少ないため、HTTP フレーム ヘッダーのメタデータは JSON に変換されます。 センダーとリレー HTTP ゲートウェイ間のリレーションシップにのみ関連する HTTP メタデータ (承認情報を含む) は転送されません。 HTTP 要求本文は、バイナリ WebSocket フレームとして透過的に転送されます。

リスナーは、同等の応答ジェスチャを使用して HTTP 要求に応答できます。

要求/応答フローは既定ではコントロール チャネルを使いますが、必要なときはいつでも、個別のランデブー WebSocket に "アップグレード" できます。 個別の WebSocket 接続を使うと、各クライアント会話のスループットは向上しますが、リスナーが処理する必要のある接続の負担が増え、軽量クライアントには望ましくない可能性があります。

コントロール チャネルでは、要求および応答の本文のサイズは最大 64 KB に制限されます。 HTTP ヘッダー メタデータは、合計で 32 KB に制限されます。 要求または応答がしきい値を超えた場合、リスナーは 受け入れの処理と同等のジェスチャを使うランデブー WebSocket にアップグレードする必要があります。

要求の場合は、サービスがコントロール チャネル経由で要求をルーティングするかどうかを決定します。 これには、要求が (ヘッダーと本文で) 完全に 64 KB を超える場合、または要求が "チャンク" 転送エンコードで送信されていて、要求が 64 KB を超えると予想される理由がサービスにある場合や要求の読み取りが瞬時ではない場合などが含まれます (それ以外の場合もあります)。 サービスがランデブーを介して要求を配信することを選択した場合、ランデブー アドレスのみをリスナーに渡します。 その後、リスナーはランデブー WebSocket を確立する必要があり、サービスはランデブー WebSocket 経由で本文を含む完全な要求をすぐに配信します。 応答もランデブー WebSocket を使う必要があります。

コントロール チャネル経由で到着する要求の場合、リスナーはコントロール チャネルまたはランデブーのどちらで応答するかを決定します。 サービスは、コントロール チャネル経由でルーティングされるすべての要求にランデブー アドレスを含める必要があります。 このアドレスは、現在の要求からアップグレードする場合にのみ有効です。

リスナーは、アップグレードを選択した場合、接続し、確立されたランデブー ソケットを使ってすぐに応答を配信します。

ランデブー WebSocket が確立されると、リスナーは同じクライアントからの要求と応答を処理するためにそれを維持する必要があります。 サービスは、センダーとの HTTPS ソケット接続が存続する限り WebSocket を保持し、そのセンダーからの以降のすべての要求を、保持されている WebSocket 経由でルーティングします。 リスナー側がランデブー WebSocket の削除を選択した場合、サービスも、後続の要求が既に進行中かどうかに関係なく、センダーへの接続を削除します。

更新操作

リスナーの登録とコントロール チャネルの維持に必要なセキュリティ トークンは、リスナーがアクティブである間に有効期限が切れる可能性もあります。 トークンの期限切れは進行中の接続には影響しませんが、コントロール チャネルは期限切れの瞬間 (または直後) にサービスによって破棄されます。 "更新" 操作には、JSON メッセージが使用されます。リスナーはこのメッセージを送信し、コントロール チャネルに関連付けられているトークンを差し替えることで、コントロール チャネルが維持される期間を延長することができます。

ping 操作

コントロール チャネルがアイドル状態で長時間経過した場合、その途中に存在するロード バランサーや NAT が TCP 接続を失う可能性があります。 これは "ping" 操作によって防ぐことができます。チャネル上に少量のデータを送信することで、その接続がまだ使用中であることをネットワーク ルート上のすべての当事者に伝えます。これは、リスナーの "存続性" テストとしての機能も果たしています。 ping が失敗した場合、コントロール チャネルは使用不可と考えられるので、リスナーは再接続する必要があります。

送信側の対話

センダーには 2 つの対話が存在します。つまり、Web ソケットに接続するか、または HTTPS 経由で要求を送信します。 センダー ロールから Web ソケット経由で要求を送信することはできません。

接続操作

サービス上の WebSocket は、"接続" 操作によって開かれます。その際、ハイブリッド接続の名前のほか、必要に応じて (ただし既定では必須) "送信" アクセス許可を付与するセキュリティ トークンをクエリ文字列で指定します。 その後、サービスが前述した方法でリスナーと対話し、その WebSocket につながるランデブー接続の作成をリスナーに要求します。 WebSocket が受け入れられると、以後 WebSocket 上のすべての対話は、接続先のリスナーとの間で行われるようになります。

要求操作

機能が有効にされているハイブリッド接続の場合、センダーはリスナーにほぼ無制限の HTTP 要求を送信することができます。

クエリ文字列または要求の HTTP ヘッダーに埋め込まれているリレー アクセス トークンを除き、リレーはリレー アドレスおよびリレー アドレス パスのすべてのサフィックスでのすべての HTTP 操作に対して完全に透過的であり、リスナーはエンドツー エンドの承認や、CORS などの HTTP 拡張機能さえ、完全に制御できます。

リレー エンドポイントでのセンダーの認証は、既定でオンになりますが、オプションです。 ハイブリッド接続の所有者は、匿名センダーを許可するかどうかを選択できます。 サービスは、次のようにして、承認情報を傍受、検査、および除去します。

  1. クエリ文字列に sb-hc-token 式が含まれる場合、式は常にクエリ文字列から除去されます。 これは、リレー認証が有効になっている場合に評価されます。
  2. 要求ヘッダーに ServiceBusAuthorization ヘッダーが含まれている場合、ヘッダー式はヘッダー コレクションから常に除去されます。 これは、リレー認証が有効になっている場合に評価されます。
  3. リレー認証が有効になっていて、要求ヘッダーに Authorization ヘッダーが含まれ、前のどの式も存在しない場合にのみ、ヘッダーは評価および削除されます。 それ以外の場合、Authorization は常にそのまま渡されます。

アクティブなリスナーがない場合、サービスは 502 "無効なゲートウェイ" エラー コードを返します。 サービスが要求を処理していないように見える場合、サービスは 60 秒後に 504 "ゲートウェイ タイムアウト" を返します。

対話の概要

この対話モデルで最終的にセンダー クライアントは、"クリーン" な WebSocket とのハンドシェイクが済んでいることになります。WebSocket はリスナーに接続されており、それ以降、プリアンブル データや接続のための準備は必要ありません。 したがってこのモデルでは、既存の WebSocket クライアントはどのような実装であれ、正しく構築された URL をその WebSocket クライアント レイヤーに渡すだけで、ハイブリッド接続サービスを簡単に利用することができます。

リスナーが受け入れ段階の対話を通じて取得するランデブー接続の WebSocket もクリーンであり、ごくわずかな抽象化処理 (自己のフレームワークのローカル ネットワーク リスナーにおける "受け入れ" 操作とハイブリッド接続のリモート "受け入れ" 操作を識別するための処理) を加えるだけで、既存の WebSocket サーバーの実装に渡すことができます。

HTTP 要求/応答モデルは、センダーに、オプションの承認レイヤーを含むほぼ無制限の HTTP プロトコル サーフェス領域を提供します。 リスナーは、HTTP 本文を保持するバイナリ フレームを含む解析済みの HTTP 要求ヘッダー セクションを取得します。これは、ダウンストリームの HTTP 要求で戻すことも、そのまま処理することもできます。 応答では、同じ形式を使用します。 64 KB 未満の要求および応答本文を使用する対話は、すべてのセンダーが共有する 1 つの Web ソケット上で処理できます。 さらに大きい要求と応答は、ランデブー モデルを使って処理できます。

プロトコル リファレンス

このセクションでは、これまでに説明したプロトコルの対話について詳しく説明します。

HTTPS 1.1 からの改良点として、すべての WebSocket 接続はポート 443 上に作成されます。これは一部の WebSocket フレームワークや API で一般的に抽象化されています。 実装の中立性を維持するために、ここでは特定のフレームワークを推奨することはしません。

リスナーのプロトコル

リスナーのプロトコルは、2 つの接続ジェスチャと 3 つのメッセージ操作とで構成されます。

リスナーのコントロール チャネル接続

コントロール チャネルは、次のアドレスに対する WebSocket 接続を作成することによって開かれます。

wss://{namespace-address}/$hc/{path}?sb-hc-action=...[&sb-hc-id=...]&sb-hc-token=...

namespace-address は、ハイブリッド接続のホストとなる Azure Relay 名前空間の完全修飾ドメイン名です。通常、{myname}.servicebus.windows.net の形式で指定します。

クエリ文字列パラメーターのオプションは次のとおりです。

パラメーター 必須 説明設定
sb-hc-action はい リスナー ロールの場合、このパラメーターには sb-hc-action=listen を指定する必要があります。
{path} はい このリスナーを登録するあらかじめ構成されたハイブリッド接続の名前空間パスを URL エンコードしたもの。 この式がパスの固定部分 $hc/ に付加されます。
sb-hc-token あり* リスナーは、名前空間またはハイブリッド接続のリッスン権限を付与する有効な Service Bus 共有アクセス トークンを URL エンコードして指定する必要があります。
sb-hc-id いいえ クライアント側から任意で指定される ID です。この ID によってエンド ツー エンドの診断トレースが可能となります。

何らかのエラー (ハイブリッド接続パスが登録されていない、トークンが無効、トークンが欠落しているなど) が原因で WebSocket 接続に失敗した場合、通常の HTTP 1.1 ステータス フィードバック モデルを使用してエラー フィードバックが返されます。 Azure サポートには、この状態の説明に記述されているエラー追跡 ID を伝えることができます。

コード エラー 説明
404 Not Found ハイブリッド接続のパスが無効か、ベース URL の形式に誤りがあります。
401 権限がありません セキュリティ トークンが欠落しているか、形式に誤りがあるか、無効です。
403 許可されていません このパスと操作の組み合わせに対してセキュリティ トークンが無効です。
500 内部エラー サービス内で何らかの問題が発生しました。

WebSocket 接続が最初にセットアップされた後、サービスによって意図的にシャットダウンされた場合は、その理由が、WebSocket プロトコルの適切なエラー コードを使用して、エラー メッセージと共に伝達されます。エラー メッセージには追跡 ID も記述されます。 エラー状態が発生していなければ、コントロール チャネルがサービスによってシャットダウンされることはありません。 正常な終了処理によるシャットダウンはすべてクライアント側の制御となります。

Web ソケットの状態 説明
1001 ハイブリッド接続のパスが削除されたか無効です。
1008 セキュリティ トークンが有効期限切れとなり、承認ポリシーに違反した状態です。
1011 サービス内で何らかの問題が発生しました。

受け入れのハンドシェイク

"受け入れ" 通知は、WebSocket のテキスト フレームに JSON メッセージとして格納され、既に確立されているコントロール チャネルを介してサービスからリスナーに送信されます。 このメッセージに対する応答はありません。

このメッセージには、"accept" という名前の JSON オブジェクトが含まれています。このオブジェクトには現時点で、次のプロパティが定義されています。

  • address - URL 文字列。受信接続を受け入れるための WebSocket をサービスに対して確立する目的で使用されます。
  • id - この接続の一意の識別子。 ID がセンダー クライアントによって指定された場合、これはセンダーによって指定された値になります。それ以外の場合は、システムによって生成された値になります。
  • connectHeaders - センダーから Relay エンドポイントに提供されたすべての HTTP ヘッダー。Sec-WebSocket-Protocol ヘッダーと Sec-WebSocket-Extensions ヘッダーも含まれています。
{
    "accept" : {
        "address" : "wss://dc-node.servicebus.windows.net:443/$hc/{path}?...",
        "id" : "4cb542c3-047a-4d40-a19f-bdc66441e736",
        "connectHeaders" : {
            "Host" : "...",
            "Sec-WebSocket-Protocol" : "...",
            "Sec-WebSocket-Extensions" : "..."
        }
     }
}

リスナーは、JSON メッセージとして提供されたアドレスの URL を使用して、センダー ソケットを許可または拒否するための WebSocket を確立します。

ソケットの受け入れ

リスナーは、ソケットを受け入れるために、指定されたアドレスに対して WebSocket 接続を確立します。

"受け入れ" メッセージに Sec-WebSocket-Protocol ヘッダーがある場合、リスナーは WebSocket のみを受け入れます (リスナーがこのプロトコルをサポートしている場合)。 次いで、リスナーは WebSocket が確立されたものとしてヘッダーを設定します。

Sec-WebSocket-Extensions ヘッダーも同様です。 フレームワークが拡張機能をサポートしている場合、拡張機能に必要な Sec-WebSocket-Extensions ハンドシェイクの、"サーバー" 側の応答に対してヘッダーを設定する必要があります。

受け入れソケットを確立するためには URL をそのまま使用してください。ただし、次のパラメーターを含める必要があります。

パラメーター 必須 説明設定
sb-hc-action はい ソケットを受け入れるためには、このパラメーターを sb-hc-action=accept とする必要がある
{path} はい (次の段落を参照)
sb-hc-id いいえ id のこれまでの説明を参照してください。

{path} は、このリスナーを登録するあらかじめ構成されたハイブリッド接続の名前空間パスを URL エンコードしたものです。 この式がパスの固定部分 $hc/ に付加されます。

path 式は、サフィックスおよびクエリ文字列式、区切り文字スラッシュ、登録されている名前を使って、拡張することができます。 このパラメーターを使用すると、センダー クライアントは、HTTP ヘッダーを含めることができない場合に、ディスパッチ引数を受け入れ側リスナーに渡すことができます。 リスナー フレームワークは、パスから固定パス部分と登録名を解析し、おそらくプレフィックス sb- が付いたクエリ文字列引数を除いて、残りの部分をアプリケーションが接続可否決定に使用できるようにするものと想定されます。

詳細については、後の「センダーのプロトコル」セクションを参照してください。

エラーが発生した場合、サービスから次のような応答が返される可能性があります。

コード エラー 説明
403 許可されていません URL が無効です。
500 内部エラー サービス内で何らかの問題が発生しました。

接続が確立された後、センダーの WebSocket がシャットダウンするか、次の状態に該当した場合、WebSocket はサーバーによってシャットダウンされます。

Web ソケットの状態 説明
1001 センダー クライアントによって接続がシャットダウンされています。
1001 ハイブリッド接続のパスが削除されたか無効です。
1008 セキュリティ トークンが有効期限切れとなり、承認ポリシーに違反した状態です。
1011 サービス内で何らかの問題が発生しました。
ソケットの拒否

accept メッセージを検査したうえでソケットを拒否する場合、拒否の理由を伝える状態コードと状態の説明をセンダーに送り返すために同様のハンドシェイクが必要となります。

ここでは、プロトコル デザインの選択肢として、WebSocket ハンドシェイク (つまり、決まったエラー状態となるように設計されているハンドシェイク) を使用することにします。そうすればリスナー クライアントの実装で引き続き WebSocket クライアントを使用でき、素の HTTP クライアントを別途採用する必要はありません。

ソケットを拒否する場合、クライアントは、accept メッセージからアドレス URI を取得し、次の 2 つのクエリ文字列パラメーターを追加します。

Param 必須 説明
sb-hc-statusCode はい HTTP 状態コード (数値)
sb-hc-statusDescription はい 人が判読できる形式で記述された拒否の理由。

最終的に構築された URI を使用して WebSocket 接続が確立されます。

正しく完了するとき、このハンドシェイクは、意図的に HTTP エラー コード 410 で失敗します。これは WebSocket がまだ確立されていないためです。 問題が生じた場合は、次のコードがエラーについての説明となります。

コード エラー 説明
403 許可されていません URL が無効です。
500 内部エラー サービス内で何らかの問題が発生しました。

要求メッセージ

requestコントロール チャネル経由でに、メッセージをサービスによってリスナーに送信します。 同じメッセージが、確立された後のランデブー WebSocket 経由でも送信されます。

request は、ヘッダーとバイナリ本文フレームの 2 つの部分で構成されます。 本文がない場合、本文フレームは省略されます。 ブール型の body プロパティは、本文が要求メッセージ内に存在するかどうかを示します。

要求本文がある要求の構造は次のようになります。

----- Web Socket text frame ----
{
    "request" :
    {
        "body" : true,
        ...
    }
}
----- Web Socket binary frame ----
FEFEFEFEFEFEFEFEFEFEF...
----- Web Socket binary frame ----
FEFEFEFEFEFEFEFEFEFEF...
----- Web Socket binary frame -FIN
FEFEFEFEFEFEFEFEFEFEF...
----------------------------------

リスナーは、複数のバイナリ フレームに分割された要求本文の受信を処理する必要があります (WebSocket のフラグメントに関する説明をご覧ください)。 FIN フラグが設定されたバイナリ フレームを受信すると、要求は終了します。

本文のない要求の場合、テキスト フレームは 1 つだけです。

----- Web Socket text frame ----
{
    "request" :
    {
        "body" : false,
        ...
    }
}
----------------------------------

request の JSON コンテンツは次のとおりです。

  • address - URI 文字列。 これは、この要求に使用するランデブー アドレスです。 受信要求が 64 KB より大きい場合、このメッセージの残りの部分は空のままになり、クライアントは後で説明する accept 操作と同等のランデブー ハンドシェイクを開始する必要があります。 その後、サービスは完全な request を確立された Web ソケットに配置します。 応答が 64 KB を超えると予想される場合は、リスナーもランデブー ハンドシェイクを開始し、確立された Web ソケット経由で応答を転送する必要があります。

  • id – 文字列。 この要求の一意識別子です。

  • requestHeaders – このオブジェクトには、センダーによってエンドポイントに提供されたすべての HTTP ヘッダーと (で説明したように承認情報は除きます)、ゲートウェイとの接続に厳密に関連するヘッダーが含まれます。 具体的には、RFC7230 において定義または予約されているすべてのヘッダー (Via を除きます) は、削除されて転送されません。

    • Connection (RFC7230、セクション 6.1)
    • Content-Length (RFC7230、セクション 3.3.2)
    • Host (RFC7230、セクション 5.4)
    • TE (RFC7230、セクション 4.3)
    • Trailer (RFC7230、セクション 4.4)
    • Transfer-Encoding (RFC7230、セクション 3.3.1)
    • Upgrade (RFC7230、セクション 6.7)
    • Close (RFC7230、セクション 8.1)
  • requestTarget – 文字列。 このプロパティは、要求の "要求ターゲット" (RFC7230、セクション 5.3) を保持します。 これには、プレフィックス sb-hc- が付いたすべてのパラメーターが除去されたクエリ文字列部分が含まれます。

  • method - 文字列。 これは、RFC7231、セクション 4 に従った、要求のメソッドです。 CONNECT メソッドを使うことはできません。

  • body – ブール値。 1 つ以上のバイナリ本文フレームが後に続くかどうかを示します。

{
    "request" : {
        "address" : "wss://dc-node.servicebus.windows.net:443/$hc/{path}?...",
        "id" : "42c34cb5-7a04-4d40-a19f-bdc66441e736",
        "requestTarget" : "/abc/def?myarg=value&otherarg=...",
        "method" : "GET",
        "requestHeaders" : {
            "Host" : "...",
            "Content-Type" : "...",
            "User-Agent" : "..."
        },
        "body" : true
     }
}
要求への応答

受信側は応答する必要があります。 接続を維持しながら要求への応答に繰り返し失敗すると、リスナーはブロックされることがあります。

応答は任意の順序で送信できますが、各要求に 60 秒以内に応答する必要があり、できないと配信は失敗として報告されます。 60 秒の期限は、response フレームがサービスによって受信されるまでカウントされます。 複数のバイナリ フレームを含む進行中の応答は、60 秒以上アイドル状態になることはできず、そうなった場合は終了します。

コントロール チャネル経由で要求を受信した場合、応答は、要求を受信した場所からコントロール チャネルで送信するか、またはランデブー チャネル経由で送信する必要があります。

応答は、"response" という名前の JSON オブジェクトです。 本文の内容の処理規則は、request メッセージとまったく同じであり、body プロパティに基づきます。

  • requestId – 文字列。 REQUIRED. (必須。) 応答される request メッセージの id プロパティの値。
  • statusCode – 数値。 REQUIRED. (必須。) 通知の結果を示す数値の HTTP 状態コード。 502 "Bad Gateway"504 "Gateway Timeout" を除く、RFC7231、セクション 6 のすべての状態コードが許可されます。
  • statusDescription - 文字列。 省略可能。 RFC7230、セクション 3.1.2 に従う HTTP 状態コードの理由テキスト
  • responseHeaders – 外部 HTTP 応答で設定される HTTP ヘッダー。 request と同様に、RFC7230 で定義済みのヘッダーを使うことはできません。
  • body – ブール値。 バイナリの本文フレームが後に続くかどうかを示します。
----- Web Socket text frame ----
{
    "response" : {
        "requestId" : "42c34cb5-7a04-4d40-a19f-bdc66441e736",
        "statusCode" : "200",
        "responseHeaders" : {
            "Content-Type" : "application/json",
            "Content-Encoding" : "gzip"
        }
         "body" : true
     }
}
----- Web Socket binary frame -FIN
{ "hey" : "mydata" }
----------------------------------
ランデブー経由の応答

64 KB を超える応答の場合、ランデブー ソケット経由で応答を配信する必要があります。 また、要求が 64 KB より大きく、request のみがアドレス フィールドが含む場合は、request を取得するためにランデブー ソケットを確立する必要があります。 ランデブー ソケットが確立された後、対応するクライアントへの応答およびそれ以降の対応するクライアントからの要求は、ランデブー ソケットが存在している間は、それを介して配信される必要があります。

ランデブー ソケットの確立には、requestaddress URL をそのまま使う必要があります。ただし、次のパラメーターを含める必要があります。

パラメーター 必須 説明設定
sb-hc-action はい ソケットを受け入れるためには、このパラメーターを sb-hc-action=request とする必要がある

エラーが発生した場合、サービスから次のような応答が返される可能性があります。

コード エラー 説明
400 無効な要求 認識されないアクション、または URL が無効です。
403 許可されていません URL の有効期限が切れています。
500 内部エラー サービス内で何らかの問題が発生しました。

接続が確立された後、クライアントの HTTP ソケットがシャットダウンするか、次の状態に該当した場合、WebSocket はサーバーによってシャットダウンされます。

Web ソケットの状態 説明
1001 センダー クライアントによって接続がシャットダウンされています。
1001 ハイブリッド接続のパスが削除されたか無効です。
1008 セキュリティ トークンが有効期限切れとなり、承認ポリシーに違反した状態です。
1011 サービス内で何らかの問題が発生しました。

リスナーのトークン更新

リスナーのトークンの有効期限が切れそうになったときは、確立済みのコントロール チャネルを介してリスナーからサービスにテキスト フレーム メッセージを送信すれば、トークンを差し替えることができます。 このメッセージには、renewToken という名前の JSON オブジェクトが含まれています。このオブジェクトには現時点で、次のプロパティが定義されています。

  • token – 名前空間またはハイブリッド接続のリッスン権限を付与する有効な Service Bus 共有アクセス トークンを URL エンコードして指定する必要があります。
{
  "renewToken": {
    "token":
      "SharedAccessSignature sr=http%3a%2f%2fcontoso.servicebus.windows.net%2fhyco%2f&sig=XXXXXXXXXX%3d&se=1471633754&skn=SasKeyName"
  }
}

トークンの検証に失敗した場合、アクセスは拒否され、コントロール チャネルの WebSocket は、クラウド サービスによってエラーと共にクローズされます。 それ以外の場合、応答は返されません。

Web ソケットの状態 説明
1008 セキュリティ トークンが有効期限切れとなり、承認ポリシーに違反した状態です。

Web ソケット接続プロトコル

センダーのプロトコルは、リスナーの確立方法とほぼ同じです。 エンド ツー エンドで WebSocket の存在をできるだけ目立たなくすることが目的となります。 接続先のアドレスはリスナーの場合と同じですが、"action" が異なるほか、トークンに必要なアクセス許可が異なります。

wss://{namespace-address}/$hc/{path}?sb-hc-action=...&sb-hc-id=...&sb-hc-token=...

namespace-address は、ハイブリッド接続のホストとなる Azure Relay 名前空間の完全修飾ドメイン名です。通常、{myname}.servicebus.windows.net の形式で指定します。

要求には、追加の HTTP ヘッダー (アプリケーション定義のヘッダーなど) を含めることができます。 指定したヘッダーはすべてリスナーに渡され、accept 制御メッセージの connectHeader オブジェクトで確認できます。

クエリ文字列パラメーターのオプションは次のとおりです。

Param 必須 説明
sb-hc-action はい センダー ロールの場合、このパラメーターには sb-hc-action=connect を指定する必要があります。
{path} はい (次の段落を参照)
sb-hc-token あり* リスナーは、名前空間またはハイブリッド接続の送信権限を付与する有効な Service Bus 共有アクセス トークンを URL エンコードして指定する必要があります。
sb-hc-id いいえ ID の指定は任意です。指定した場合、エンド ツー エンドの診断トレースが可能になるほか、受け入れハンドシェイク時にリスナーに伝えられます。

{path} は、このリスナーを登録するあらかじめ構成されたハイブリッド接続の名前空間パスを URL エンコードしたものです。 さらに通信するために、サフィックスとクエリ文字列式で path 式を拡張できます。 たとえば、ハイブリッド接続がパス hyco で登録されている場合、hyco/suffix?param=value&... の後にここで定義したクエリ文字列パラメーターを付けて path 式にできます。 完全な式は次のようなものになります。

wss://{namespace-address}/$hc/hyco/suffix?param=value&sb-hc-action=...[&sb-hc-id=...&]sb-hc-token=...

path 式は、"受け入れ" 制御メッセージに含まれるアドレス URI でリスナーに渡されます。

何らかのエラー (ハイブリッド接続パスが登録されていない、トークンが無効、トークンが欠落しているなど) が原因で WebSocket 接続に失敗した場合、通常の HTTP 1.1 ステータス フィードバック モデルを使用してエラー フィードバックが返されます。 Azure サポートには、この状態の説明に記述されているエラー追跡 ID を伝えることができます。

コード エラー 説明
404 Not Found ハイブリッド接続のパスが無効か、ベース URL の形式に誤りがあります。
401 権限がありません セキュリティ トークンが欠落しているか、形式に誤りがあるか、無効です。
403 許可されていません このパスと操作の組み合わせに対してセキュリティ トークンが無効です。
500 内部エラー サービス内で何らかの問題が発生しました。

WebSocket 接続が最初にセットアップされた後、サービスによって意図的にシャットダウンされた場合は、その理由が、WebSocket プロトコルの適切なエラー コードを使用して、エラー メッセージと共に伝達されます。エラー メッセージには追跡 ID も記述されます。

Web ソケットの状態 説明
1000 ソケットは、リスナーによってシャットダウンされました。
1001 ハイブリッド接続のパスが削除されたか無効です。
1008 セキュリティ トークンの有効期限が切れているため、承認ポリシーに違反しています。
1011 サービス内で何らかの問題が発生しました。

HTTP 要求プロトコル

HTTP 要求プロトコルは、プロトコルのアップグレードを除く、任意の HTTP 要求を許可します。 HTTP 要求は、ハイブリッド接続の WebSocket クライアントに使われる $hc インフィックスを除いて、エンティティの通常のランタイム アドレスにおいて参照されます。

https://{namespace-address}/{path}?sb-hc-token=...

namespace-address は、ハイブリッド接続のホストとなる Azure Relay 名前空間の完全修飾ドメイン名です。通常、{myname}.servicebus.windows.net の形式で指定します。

要求には、追加の HTTP ヘッダー (アプリケーション定義のヘッダーなど) を含めることができます。 RFC7230 (「要求メッセージ」を参照) で直接定義されているものを除き、提供されたすべてのヘッダーはリスナーにフローし、要求メッセージの requestHeader オブジェクトで見つけることができます。

クエリ文字列パラメーターのオプションは次のとおりです。

Param 必須 説明
sb-hc-token あり* リスナーは、名前空間またはハイブリッド接続の送信権限を付与する有効な Service Bus 共有アクセス トークンを URL エンコードして指定する必要があります。

トークンは、ServiceBusAuthorization または Authorization HTTP ヘッダーで伝達することもできます。 匿名要求を許可するようにハイブリッド接続が構成されている場合は、トークンを省略できます。

サービスは実質的にプロキシとして機能するため、本当の HTTP プロキシではなくても、RFC7230、セクション 5.7.1 に準拠している Via ヘッダーを追加するか、既存の Via ヘッダーに注釈を付けます。 サービスは、リレー名前空間ホスト名を Via に追加します。

コード Message 説明
200 OK 要求は、少なくとも 1 つのリスナーによって処理されました。
202 Accepted 要求は、少なくとも 1 つのリスナーによって受け付けられました。

エラーが発生した場合、サービスから次のような応答が返される可能性があります。 応答がサービスまたはリスナーから送信されたかどうかは、Via ヘッダーの存在によって識別できます。 ヘッダーが存在する場合、応答はリスナーからです。

コード エラー 説明
404 Not Found ハイブリッド接続のパスが無効か、ベース URL の形式に誤りがあります。
401 権限がありません セキュリティ トークンが欠落しているか、形式に誤りがあるか、無効です。
403 許可されていません このパスと操作の組み合わせに対してセキュリティ トークンが無効です。
500 内部エラー サービス内で何らかの問題が発生しました。
503 誤ったゲートウェイ 要求はどのリスナーにもルーティングできませんでした。
504 ゲートウェイのタイムアウト 要求はリスナーにルーティングされましたが、リスナーでは必要な時間内に受信が確認されませんでした。

次のステップ