次の方法で共有


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 つのクライアント実装が用意されています。 これらの実装は、次を対象とします。

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 インスタンスを構築できるビルダーが用意されています。 ビルダーは NettyAsyncHttpClientBuilderOkHttpAsyncHttpClientBuilderJdkAsyncHttpClientBuilder です。

次の例は、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 pipeline diagram

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 でプロキシを構成する」を参照してください。