Azure SDK for Java の HTTP クライアントとパイプライン
この記事では、Azure SDK for Java 内での HTTP クライアントとパイプライン機能の使用の概要について説明します。 この機能は、すべての Azure SDK for Java ライブラリを使用する開発者に、一貫性のある強力で柔軟なエクスペリエンスを提供します。
HTTP クライアント
Azure SDK for Java は、HttpClient
の抽象化を使用して実装されます。 この抽象化により、複数の HTTP クライアント ライブラリまたはカスタム実装を受け入れるプラグ可能なアーキテクチャが可能になります。 ただし、ほとんどのユーザーの依存関係の管理を簡素化するために、すべての Azure クライアント ライブラリは azure-core-http-netty
に依存しています。 そのため、すべての Azure SDK for Java ライブラリで使用される既定のクライアントは Netty HTTP クライアントです。
Netty が既定の HTTP クライアントですが、SDK には、お使いのプロジェクトに既に存在する依存関係に応じて 3 つのクライアント実装が用意されています。 これらの実装は、次を対象とします。
- Netty
- OkHttp
- JDK 11 で導入された新しい HttpClient
Note
AZURE SDK for Java と組み合わせた JDK HttpClient
は、JDK 12 以降でのみサポートされています。
既定の HTTP クライアントを置き換える
別の実装を使用する場合は、Netty の依存関係をビルド構成ファイルで除外することでこれを削除できます。 Maven の pom.xml ファイルで、Netty 依存関係を除外し、別の依存関係を含めます。
次の例では、azure-security-keyvault-secrets
ライブラリの実際の依存関係から Netty 依存関係を除外する方法を示します。 ここに示すように、適切なすべての com.azure
ライブラリから Netty を除外するようにしてください。
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-security-keyvault-secrets</artifactId>
<version>4.2.2.</version>
<exclusions>
<exclusion>
<groupId>com.azure</groupId>
<artifactId>azure-core-http-netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core-http-okhttp</artifactId>
<version>1.3.3</version>
</dependency>
Note
Netty 依存関係を削除しても、代替の実装を指定しない場合、アプリケーションは起動できません。 HttpClient
の実装がクラスパスに存在している必要があります。
HTTP クライアントを構成する
サービス クライアントを構築すると、デフォルトで HttpClient.createDefault()
が使用されます。 このメソッドは、指定された HTTP クライアントの実装に基づいて、基本的な HttpClient
インスタンスを返します。 プロキシなどのより複雑な HTTP クライアントが必要な場合に備えて、各実装には、構成済みの HttpClient
インスタンスを構築できるビルダーが用意されています。 ビルダーは NettyAsyncHttpClientBuilder
、OkHttpAsyncHttpClientBuilder
、JdkAsyncHttpClientBuilder
です。
次の例は、Netty、OkHttp、JDK 11 HTTP クライアントを使用して HttpClient
インスタンスを構築する方法を示しています。 これらのインスタンスは、http://localhost:3128
を使用してプロキシを行い、ユーザー example とパスワード weakPassword を使用して認証を行います。
// Netty
HttpClient httpClient = new NettyAsyncHttpClientBuilder()
.proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 3128))
.setCredentials("example", "weakPassword"))
.build();
// OkHttp
HttpClient httpClient = new OkHttpAsyncHttpClientBuilder()
.proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 3128))
.setCredentials("example", "weakPassword"))
.build();
// JDK 11 HttpClient
HttpClient client = new JdkAsyncHttpClientBuilder()
.proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 3128))
.setCredentials("example", "weakPassword"))
.build();
これで、構築された HttpClient
インスタンスをサービス クライアント ビルダーに渡して、サービスと通信するためのクライアントとして使用できるようになりました。 次の例では、新しい HttpClient
インスタンスを使用して、Azure Storage Blob クライアントを構築します。
BlobClient blobClient = new BlobClientBuilder()
.connectionString(<connection string>)
.containerName("container")
.blobName("blob")
.httpClient(httpClient)
.build();
管理ライブラリについては、マネージャーの構成時に HttpClient
を設定できます。
AzureResourceManager azureResourceManager = AzureResourceManager.configure()
.withHttpClient(httpClient)
.authenticate(credential, profile)
.withDefaultSubscription();
HTTP パイプライン
HTTP パイプラインは、Azure の Java クライアント ライブラリでの一貫性と診断可能性を確保する上で重要なコンポーネントの 1 つです。 HTTP パイプラインは次のもので構成されます。
- HTTP トランスポート
- HTTP パイプライン ポリシー
クライアントを作成する際に、独自のカスタム HTTP パイプラインを指定できます。 パイプラインを指定しない場合、クライアント ライブラリは、その特定のクライアント ライブラリで動作するように構成されたパイプラインを作成します。
HTTP トランスポート
HTTP トランスポートは、サーバーへの接続の確立と、HTTP メッセージの送受信を行います。 HTTP トランスポートは、Azure サービスと対話するための Azure SDK クライアント ライブラリのゲートウェイを形成します。 この記事で既に説明したように、Azure SDK for Java は、HTTP トランスポートに対して既定で Netty を使用します。 ただし、この SDK にはプラグ可能な HTTP トランスポートも用意されているので、必要に応じて他の実装を使用できます。 この SDK には、OkHttp 用と、JDK 11 以降に付属する HTTP クライアント用に、さらに 2 つの HTTP トランスポート実装が用意されています。
HTTP パイプライン ポリシー
パイプラインは、HTTP 要求と応答のラウンドトリップごとに実行される一連の手順で構成されます。 各ポリシーには特定の目的があり、要求または応答、あるいはその両方に対して動作します。 すべてのクライアント ライブラリには標準の "Azure Core" レイヤーがあり、このレイヤーによって、各ポリシーがパイプライン内で順番に実行されるようになります。 要求を送信すると、ポリシーはパイプラインに追加された順序で実行されます。 サービスから応答を受信すると、ポリシーは逆の順序で実行されます。 パイプラインに追加されたすべてのポリシーは、要求を送信する前と応答を受信した後に実行されます。 ポリシーは、要求と応答のどちらか、またはその両方に対して動作するかどうかを決定する必要があります。 たとえば、ロギング ポリシーは要求と応答をログに記録しますが、認証ポリシーは要求の変更のみに関心があります。
Azure Core フレームワークは、ポリシーを実行するために必要なコンテキストと共に、必要な要求および応答データをポリシーに提供します。 その後ポリシーは、提供されたデータを使用して操作を実行し、パイプラインの次のポリシーに制御を渡すことができます。
HTTP パイプライン ポリシーの位置
クラウド サービスに HTTP 要求を行う場合は、一時的なエラーを処理し、失敗した試行を再試行することが重要です。 この機能は一般的な要件であるため、Azure Core は、一時的なエラーを監視し、自動的に要求を再試行できる再試行ポリシーを提供しています。
したがって、この再試行ポリシーによって、パイプライン全体が、再試行ポリシーの前に実行されるポリシーと、再試行ポリシーの後に実行されるポリシーの 2 つの部分に分割されます。 再試行ポリシーの前に追加されたポリシーは、API 操作ごとに 1 回だけ実行され、再試行ポリシーの後に追加されたポリシーは、再試行の回数だけ実行されます。
そのため、HTTP パイプラインを構築するときは、ポリシーを要求の再試行ごとに実行するのか、API 操作ごとに 1 回実行するのかを理解しておく必要があります。
一般的な HTTP パイプライン ポリシー
REST ベース サービスの HTTP パイプラインには、認証、再試行、ログ、テレメトリ、およびヘッダー内の要求 ID の指定に関するポリシーが構成されています。 Azure Core には、パイプラインに追加できる一般的に必要なこれらの HTTP ポリシーが事前に読み込まれています。
ポリシー | GitHub のリンク |
---|---|
再試行ポリシー | RetryPolicy.java |
認証ポリシー | BearerTokenAuthenticationPolicy.java |
ログ ポリシー | HttpLoggingPolicy.java |
要求 ID ポリシー | RequestIdPolicy.java |
テレメトリ ポリシー | UserAgentPolicy.java |
カスタムの HTTP パイプライン ポリシー
HTTP パイプライン ポリシーは、要求と応答を変更または修飾するための便利なメカニズムを提供します。 ユーザーまたはクライアント ライブラリ開発者によって作成されたカスタム ポリシーをパイプラインに追加することができます。 ポリシーをパイプラインに追加する際に、このポリシーを呼び出しごとに実行するのか、または再試行ごとに実行するのかを指定できます。
カスタムの HTTP パイプライン ポリシーを作成するには、基本ポリシー型を拡張して抽象メソッドを実装するだけで済みます。 その後、ポリシーをパイプラインにプラグインできます。
HTTP 要求のカスタム ヘッダー
Azure SDK for Java クライアント ライブラリは、次の例に示すように、パブリック API の Context
オブジェクトを通じてカスタマイズされたヘッダーを定義する一貫した方法を提供します。
// Add your headers
HttpHeaders headers = new HttpHeaders();
headers.set("my-header1", "my-header1-value");
headers.set("my-header2", "my-header2-value");
headers.set("my-header3", "my-header3-value");
// Call API by passing headers in Context.
configurationClient.addConfigurationSettingWithResponse(
new ConfigurationSetting().setKey("key").setValue("value"),
new Context(AddHeadersFromContextPolicy.AZURE_REQUEST_HTTP_HEADERS_KEY, headers));
// The three headers are now be added to the outgoing HTTP request.
詳細については、「AddHeadersFromContextPolicy クラス」を参照してください。
既定の TLS/SSL ライブラリ
すべてのクライアント ライブラリは、Tomcat ネイティブの Boring SSL ライブラリをデフォルトで使用して、TLS/SSL 操作にネイティブレベルのパフォーマンスを実現しています。 Boring SSL ライブラリは、Linux、macOS、Windows のネイティブ ライブラリを含んだ Uber JAR であり、JDK 内のデフォルトの TLS/SSL 実装よりも優れたパフォーマンスを備えています。
Tomcat ネイティブ TLS/SSL 依存関係のサイズを小さくする
デフォルトでは、Tomcat-Native Boring SSL ライブラリの Uber JAR が Azure SDK for Java で使用されます。 この依存関係のサイズを小さくするには、次の例に示すように、netty-tcnative に従って、os
分類子との依存関係を含める必要があります。
<project>
...
<dependencies>
...
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.25.Final</version>
<classifier>${os.detected.classifier}</classifier>
</dependency>
...
</dependencies>
...
<build>
...
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.4.0.Final</version>
</extension>
</extensions>
...
</build>
...
</project>
JDK TLS/SSL を使用する
Tomcat-Native Boring SSL の代わりにデフォルトの JDK TLS/SSL を使用する場合は、Tomcat-native Boring SSL ライブラリを除外する必要があります。 テスト結果によると、JDK TLS/SSL のパフォーマンスは Tomcat-Native Boring SSL と比較して 30% 遅くなります。 com.azure:azure-core:1.28.0
を後で使用する場合、HttpClient
実装ライブラリ (com.azure:azure-core-http-netty
など) は、Tomcat-Native Boring SSL で依存関係を管理します。 依存関係を除外するには、POM ファイルに次の構成を追加します。
<project>
...
<dependencies>
...
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core-http-netty</artifactId>
<version>1.13.6</version>
<exclusions>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
</exclusion>
</exclusions>
</dependency>
...
</dependencies>
...
</project>
次のステップ
Azure SDK for Java の HTTP クライアント機能について理解できたので、使用している HTTP クライアントをさらにカスタマイズする方法を学習します。 詳細については、「Azure SDK for Java でプロキシを構成する」を参照してください。