このページでは

Qt GRPC インターセプターの概要

インターセプターの概要

クライアント側のインターセプターは、多数のRPCに一貫して適用されるべき動作を実装するための軽量なメカニズムを提供します。これらは、次のような、特定のRPCメソッドに依存しない横断的な関心事に対して特に有用です。

  • 分散トレース
  • ロギング
  • 認証と認可
  • メトリクスと可観測性
  • ポリシーの適用
  • クライアントサイドのキャッシュ
  • フォールトインジェクション

インターセプタは、QGrpcInterceptorChain を使用してチャネルにインストールされます。各インターセプタは、1つ以上のインターセプタインターフェース(例:QGrpcStartInterceptor やQGrpcFinishedInterceptor )を実装します。Qt GRPC チャネルは、RPCのその段階に到達するたびに、対応するインターフェースを呼び出し、現在のRPCのコンテキストを提供します。

インターセプタは個々のRPCのレベルで動作します。RPCの進行に伴い、リクエストやレスポンスのメタデータおよびペイロードを検査・変更することができます。これらは、チャネルやトランスポートの設定を管理するためではなく、呼び出しごとの動作を実装することを目的としています。

注: Qt GRPC のインターセプタは チャネルにインストールされ、そのチャネルを通じて実行されるすべてのRPCに適用されます。インターセプタチェーンは構築時に固定され、その後変更することはできません。インターセプトの動作を変更するには、異なるインターセプタチェーンを持つ新しいチャネルを作成してください。

機能とフックポイント

各インターセプトインターフェースは、RPCのライフサイクルにおけるフックポイントを表します。インターセプタクラスは、多重継承を使用して複数のインターフェースを実装することができます。

Qt GRPC は、インターセプタが実装しているインターセプトインターフェースを検出し、それらをcapabilities として公開します。Qt GRPC は、これらの機能を利用して、実際に実装されているフックのみをディスパッチします。

インターフェースフックポイント方向変更可能
QGrpcStartInterceptorRPCの開始前アウトバウンド初期メッセージオブジェクト、呼び出しオプション
QGrpcWriteMessageInterceptor送信メッセージが書き込まれる前送信メッセージオブジェクト
QGrpcWritesDoneInterceptorクライアントが書き込み完了を通知したとき送信—
QGrpcCancelInterceptorRPCがキャンセルされたとき送信—
QGrpcInitialMetadataInterceptor初期メタデータを受信したとき受信時メタデータ
QGrpcMessageReceivedInterceptorメッセージのペイロードを受信したとき受信シリアライズされたメッセージデータ
QGrpcTrailingMetadataInterceptor末尾のメタデータを受信したとき受信時メタデータ
QGrpcFinishedInterceptorRPCが完了したとき受信最終ステータス

すべてのコールバックは、QGrpcInterceptionContext を受け取ります。このオブジェクトは、RPC descriptor 、channel 、または有効なcallOptions など、インターセプトされたRPCに関する情報を提供します。contextオブジェクトはコールバックの実行中のみ有効であり、その後使用してはなりません。

注: インターセプトロジックは軽量に保ち 、コールバック内でのブロック操作は避けてください。処理に時間がかかる作業(I/O やトークンの更新など)はコールバックの外側で実行し、その結果をフック内でのみ適用してください。

方向とフロー

複数のインターセプターを使用する場合、その順序は重要です。インターセプターは、アプリケーションとネットワークの間に一列に並んでいると考えると理解しやすくなります。 チェーンの先頭にあるインターセプタは、RPCを最初に処理し、次のインターセプタに渡す前にそれを変更する場合があります。ネットワークに近い位置にあるインターセプタは、実際に送信される内容を監視または調整する最後の機会を持っています。

インターセプターは、定義された順序でQGrpcInterceptorChain に追加されます。QtGrpc は、RPCが流れるにつれてチェーンを順に処理します:

  • アウトバウンド段階(アプリケーション → ネットワーク)では、コールバックはインターセプターがチェーンに追加された順序で呼び出されます。
  • インバウンドステージ(ネットワーク → アプリケーション)の場合、コールバックは逆の順序で呼び出され、これにより「ネットワークに最も近い」最後のインターセプターがインバウンドデータを最初に検知します。

発信および着信のインターセプターの方向を示す2つの図

アウトバウンドステージは、メッセージの送信や書き込みシーケンスの完了(例:writeMessage やwritesDone )など、クライアントによって開始される操作に対応します。これらのイベントは、アプリケーションからインターセプターチェーンを経由してネットワークへと伝播します。

インバウンドステージは、メッセージの受信や呼び出しの完了など、RPCによって生成されるイベントに対応します(例:messageReceived やfinished )。これらのイベントは、ネットワークからインターセプターチェーンを通ってアプリケーションへと逆方向に伝播します。

所有権とライフタイム

QGrpcInterceptorChain は、主に 2 つのライフタイムモデルをサポートしています:

  • 所有型:std::unique_ptr<T>() を使用してインターセプタを追加します。成功すると、チェーンが所有権を取得し、チェーン(ひいてはチャネル)が破棄される際にインターセプタを破棄します。
  • 非所有型(Non-owning):生ポインタ(T* )を使用してインターセプタを追加します。チェーンは所有権を取得しません。呼び出し側は、チャネルがインターセプタを呼び出す可能性がある限り、インターセプタオブジェクトが有効であり続けることを保証する必要があります。

どちらのモデルも、同じチェーン内で組み合わせることができます。所有型と非所有型のインターセプターを混在させることはサポートされていますが、非所有型のインターセプターが、それらを使用する可能性のあるすべてのチャネルよりも長く存続するように注意する必要があります。

非所有型インターセプタは、同じインターセプタインスタンスを複数のチェーンに追加することで、複数のチャネル間で共有できます。これは、共有ログや共有メトリクスの収集に役立ちますが、ライフタイムと並行アクセスの慎重な管理が必要となります。

スレッドセーフ性と共有状態

インターセプタのコールバックは、そのインターセプタ・チェーンを所有するチャネルのスレッド内で実行されます。

再入可能なインターセプタは、同期処理を一切必要としません。

同期が必要となるのは、インターセプタが複数のスレッドから使用される可能性のある共有データにアクセスする場合のみです。これは、たとえば、異なるスレッドにあるチャネルが同じインターセプタインスタンスを使用している場合や、複数のインターセプタインスタンスが同じ共有データにアクセスする場合などに発生します。

スレッド間で共有データにアクセスする必要がある場合は、インターセプタ・インスタンスをスレッドローカルに保ち、共有データを別途同期化されたオブジェクトに格納することを推奨します。

struct SharedData
{
    QReadWriteLock lock;
    // shared data protected by lock
};

class MyInterceptor : public QGrpcStartInterceptor
{
public:
    explicit MyInterceptor(std::shared_ptr<SharedData> data)
        : m_sharedData(std::move(data)) {}

    Continuation onStart(~~~) override; {
        // access shared data here
    }

private:
    std::shared_ptr<SharedData> m_sharedData;
};
~~~
auto sharedData = std::make_shared<SharedData>();
bool ok = chain1.set(
    std::make_unique<MyInterceptor>(sharedData),
    std::make_unique<MyInterceptor>(sharedData)
);
// repeats for chain2
~~~
auto channelThread1 = std::make_shared<QGrpcHttp2Channel>(
    QUrl("address:port"), std::move(chain1));
auto channelThread2 = std::make_shared<QGrpcHttp2Channel>(
    QUrl("address:port"), std::move(chain2));

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.