1前書き

このチュートリアルでは、Java 9の新しいインキュベーションhttps://docs.oracle.com/javase/9​​/docs/api/jdk/incubator/http/HttpClient.html

__.

__について探ります。

ごく最近まで、Javaは

HttpURLConnection

APIしか提供していませんでした – これは低レベルであり、機能豊富な





ユーザーフレンドリーであることは知られていません。

そのため、https://hc.apache.org/httpcomponents-client-ga/[Apache HttpClient]、http://www.eclipse.org/jetty/documentation/など、広く使用されているサードパーティ製のライブラリがよく使用されていました。 current/http-client-api.html[Jetty]、およびSpringのリンク:/rest-template[RestTemplate]。


2初期設定

  • HTTPクライアントモジュールはJDK 9でインキュベーターモジュールとしてバンドルされており** 、https://en.wikipedia.org/wiki/HTTP/2[HTTP/2]をサポートしていますが、依然としてHTTP/1.1を容易にします。

それを使用するには、

module-info.java

ファイルを使用してモジュールを定義する必要があります。これは、アプリケーションを実行するために必要なモジュールも示します。

module com.baeldung.java9.httpclient {
  requires jdk.incubator.httpclient;
}


3 HTTPクライアントAPIの概要


HttpURLConnectionとは異なり、

HTTPクライアントは同期および非同期の要求メカニズムを提供します。

APIは3つのコアクラスで構成されています。


  • HttpRequest




    を介して送信される要求を表します。


HttpClient



HttpClient


– ** は設定情報のコンテナとして振る舞う

複数のリクエストに共通


HttpResponse


– ** は、

HttpRequest

呼び出しの結果を表します

次のセクションでは、それぞれについて詳しく説明します。

まず、リクエストに注目しましょう。


4

HttpRequest



HttpRequest、

suggestという名前の



は送信したい要求を表すオブジェクトです。

HttpRequest.Builder.

を使用して新しいインスタンスを作成できます。


HttpRequest.newBuilder()

を呼び出すことで取得できます。

Builder

クラスは、リクエストを設定するために使用できる一連のメソッドを提供します。

最も重要なものをカバーします。


4.1. 設定

URI


リクエストを作成するときに最初にしなければならないことは、URLを提供することです。

これを行うには、2つの方法があります。

URI

パラメーターを指定して

Builder

のコンストラクターを使用するか、または

Builder

インスタンスでメソッド

uri(URI)

を呼び出すことです。

HttpRequest.newBuilder(new URI("https://postman-echo.com/get"))

HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))

基本的なリクエストを作成するために設定しなければならない最後のものはHTTPメソッドです。


4.2. HTTPメソッドの指定


Builder

からいずれかのメソッドを呼び出すことで、リクエストが使用するHTTPメソッドを定義できます。


  • 取得する()


  • POST(ボディプロセッサ本体)


  • PUT(ボディプロセッサ本体)


  • DELETE(BodyProcessor本体)

後で詳しくは、BodyProcessorについて説明します。それでは、

非常に単純なGETリクエストの例

を作成しましょう。

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .GET()
  .build();

このリクエストには、

HttpClient

で必要なすべてのパラメータがあります。しかし、時にはリクエストに追加のパラメータを追加する必要があります。ここにいくつかの重要なものがあります:

  • HTTPプロトコルのバージョン

  • ヘッダ

  • タイムアウト


4.3. HTTPプロトコルバージョンの設定

APIはHTTP/2プロトコルをフルに活用してデフォルトで使用しますが、使用するプロトコルのバージョンを定義できます。

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .version(HttpClient.Version.HTTP__2)
  .GET()
  .build();

ここで重要なのは、HTTP/2がサポートされていない場合、クライアントはHTTP/1.1にフォールバックするということです。


4.4. ヘッダを設定する

リクエストにヘッダを追加したい場合は、提供されているビルダーメソッドを使用できます。

これを行うには、2つの方法があります。

  • すべてのヘッダをキーと値のペアとして

    headers()

    メソッドに渡すか、または

  • 単一のKey-Valueヘッダに

    header()

    メソッドを使用する:

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .headers("key1", "value1", "key2", "value2")
  .GET()
  .build();

HttpRequest request2 = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .header("key1", "value1")
  .header("key2", "value2")
  .GET()
  .build();

リクエストをカスタマイズするために使用できる最後の便利なメソッドは

timeout()

です。


4.5. タイムアウトを設定する

それでは、回答を待つ時間を定義しましょう。

設定時間が経過すると、

HttpTimeoutException

がスローされます。デフォルトのタイムアウトは無限大に設定されています。

タイムアウトは

Duration

オブジェクトで設定できます – ビルダーインスタンスでメソッド

timeout()

を呼び出すことで:

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .timeout(Duration.of(10, SECONDS))
  .GET()
  .build();

** 5リクエストボディの設定

requestビルダーメソッドを使ってリクエストにボディを追加することができます。


POST(BodyProcessor本体)



PUT(BodyProcessor本体)

、および__DELETE(BodyProcessor本体)。

新しいAPIは、リクエストボディを渡すのを簡単にする、いくつかの

BodyProcessor

実装をそのまま提供します。


  • StringProcessor

    (で作成された

    String

    から本体を読み取ります。


HttpRequest.BodyProcessor.fromString


**

InputStreamProcessor

(で作成された

InputStream

から本文を読み取ります。


HttpRequest.BodyProcessor.fromInputStream


**

ByteArrayProcessor

(で作成されたバイト配列から本文を読み込む


HttpRequest.BodyProcessor.fromByteArray


**

FileProcessor

(指定されたパスのファイルから本文を読み込みます。


HttpRequest.BodyProcessor.fromFile

ボディが必要ない場合は、単に

HttpRequest.noBody()

を渡します。

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/post"))
  .POST(HttpRequest.noBody())
  .build();


5.1.

StringBodyProcessor



BodyProcessor

実装でリクエストボディを設定することは非常に単純で直感的です。

たとえば、単純な

String

を本体として渡したい場合は、

StringBodyProcessor

を使用できます。

すでに述べたように、このオブジェクトはファクトリメソッド

fromString()

を使って作成できます。引数として

String

オブジェクトだけを取り、それから本体を作成します。

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/post"))
  .headers("Content-Type", "text/plain;charset=UTF-8")
  .POST(HttpRequest.BodyProcessor.fromString("Sample request body"))
  .build();


5.2.

InputStreamBodyProcessor


そのためには、

InputStream



Supplier

として作成する必要があります(作成を遅延させるため)。したがって、上記の

StringBodyProcessor

とは少し異なります。

しかし、これもまた非常に簡単です。

byte[]sampleData = "Sample request body".getBytes();
HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/post"))
  .headers("Content-Type", "text/plain;charset=UTF-8")
  .POST(HttpRequest.BodyProcessor
   .fromInputStream(() -> new ByteArrayInputStream(sampleData)))
  .build();

ここでは単純な

ByteArrayInputStream

がどのように使われているかに注目してください。もちろん、任意の

InputStream

実装にすることができます。


5.3.

ByteArrayProcessor



ByteArrayProcessor

を使用して、パラメータとしてバイト配列を渡すこともできます。

byte[]sampleData = "Sample request body".getBytes();
HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/post"))
  .headers("Content-Type", "text/plain;charset=UTF-8")
  .POST(HttpRequest.BodyProcessor.fromByteArray(sampleData))
  .build();


5.4.

FileProcessor


ファイルを扱うために、提供されている

FileProcessor

を利用することができます。ファクトリメソッドは、ファイルへのパスをパラメータとして使用し、内容から本体を作成します。

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/post"))
  .headers("Content-Type", "text/plain;charset=UTF-8")
  .POST(HttpRequest.BodyProcessor.fromFile(
    Paths.get("src/test/resources/sample.txt")))
  .build();


HttpRequest

の作成方法と追加のパラメータの設定方法について説明しました。

それでは、リクエストの送信とレスポンスの受信を担当する

HttpClient

クラスについて詳しく見ていきましょう。


6.

HttpClient


すべてのリクエストは、

HttpClient.newBuilder()

メソッドを使用するか、または

HttpClient.newHttpClient()を呼び出すことによってインスタンス化できる

HttpClient__を使用して送信されます。

それは私たちが私たちの要求/応答を扱うために使うことができる多くの役に立つそして自己記述的な方法を提供します。

これらのいくつかをここでカバーしましょう。


6.1. プロキシを設定する

接続用のプロキシを定義できます。単に

Builder

インスタンスで

proxy()

メソッドを呼び出すだけです。

HttpResponse<String> response = HttpClient
  .newBuilder()
  .proxy(ProxySelector.getDefault())
  .build()
  .send(request, HttpResponse.BodyHandler.asString());

この例では、デフォルトのシステムプロキシを使用しました。


6.2. リダイレクトポリシーの設定

アクセスしたいページが別のアドレスに移動していることがあります。

その場合、通常新しいURIに関する情報と共にHTTPステータスコード3xxを受け取ります。適切なリダイレクトポリシーを設定すると、

HttpClient

は自動的にリクエストを新しいURIにリダイレクトできます。


Builder



followRedirects()

メソッドでそれを行うことができます。

HttpResponse<String> response = HttpClient.newBuilder()
  .followRedirects(HttpClient.Redirect.ALWAYS)
  .build()
  .send(request, HttpResponse.BodyHandler.asString());

すべてのポリシーはenum

HttpClient.Redirect

で定義および説明されています。


6.3. 接続に対する

Authenticator

の設定


Authenticator

は、接続用の認証情報(HTTP認証)をネゴシエートするオブジェクトです。

それは、異なる認証方式(例えば、基本認証またはダイジェスト認証など)を提供する。ほとんどの場合、認証にはサーバーに接続するためのユーザー名とパスワードが必要です。

これらの値を保持しているだけの

PasswordAuthentication

クラスを使用できます。

HttpResponse<String> response = HttpClient.newBuilder()
  .authenticator(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
      return new PasswordAuthentication(
        "username",
        "password".toCharArray());
    }
}).build()
  .send(request, HttpResponse.BodyHandler.asString());

上記の例では、ユーザー名とパスワードの値をプレーンテキストとして渡しました。もちろん、生産シナリオでは、これは違うものになります。

すべての要求が同じユーザー名とパスワードを使用するべきではないことに注意してください。


Authenticator

クラスは、どんな値が提供されるべきであるかを見つけるために使用することができるいくつかの

getXXX

(例えば、__getRequestingSite())メソッドを提供する。

それでは、新しい

HttpClient

の最も便利な機能の1つ、サーバーへの非同期呼び出しについて説明します。


6.4. リクエストを送信する – 同期と非同期

New HttpClientは、リクエストをサーバーに送信するための2つの可能性を提供します。



  • send(…​)

    – 同期的に

    (応答が来るまでブロックする)



  • sendAsync(…​)

    – 非同期

    (応答を待ちません、

ノンブロッキング)

これまでは、

send(…​)

メソッドは当然応答を待っていました。

HttpResponse<String> response = HttpClient.newBuilder()
  .build()
  .send(request, HttpResponse.BodyHandler.asString());

この呼び出しは

HttpResponse

オブジェクトを返します。アプリケーションフローからの次の命令は、応答が既にある場合にのみ実行されます。

ただし、特に大量のデータを処理している場合は、多くの欠点があります。

それで、今、私たちは

sendAsync(…​)

メソッドを使用することができます – それは

CompletableFeature <HttpResponse>

– ** を非同期的に処理するために返します:

CompletableFuture<HttpResponse<String>> response = HttpClient.newBuilder()
  .build()
  .sendAsync(request, HttpResponse.BodyHandler.asString());

新しいAPIは複数のレスポンスを処理し、リクエストボディとレスポンスボディをストリーミングすることもできます。

List<URI> targets = Arrays.asList(
  new URI("https://postman-echo.com/get?foo1=bar1"),
  new URI("https://postman-echo.com/get?foo2=bar2"));
HttpClient client = HttpClient.newHttpClient();
List<CompletableFuture<String>> futures = targets.stream()
  .map(target -> client
    .sendAsync(
      HttpRequest.newBuilder(target).GET().build(),
      HttpResponse.BodyHandler.asString())
    .thenApply(response -> response.body()))
  .collect(Collectors.toList());


6.5. 非同期呼び出しに対する

Executor

の設定

非同期呼び出しで使用されるスレッドを提供する

Executor

を定義することもできます。

このようにして、たとえば、リクエストの処理に使用されるスレッドの数を制限できます。

ExecutorService executorService = Executors.newFixedThreadPool(2);

CompletableFuture<HttpResponse<String>> response1 = HttpClient.newBuilder()
  .executor(executorService)
  .build()
  .sendAsync(request, HttpResponse.BodyHandler.asString());

CompletableFuture<HttpResponse<String>> response2 = HttpClient.newBuilder()
  .executor(executorService)
  .build()
  .sendAsync(request, HttpResponse.BodyHandler.asString());

デフォルトでは、

HttpClient

はexecutor

java.util.concurrent.Executors.newCachedThreadPool()

を使用します。


6.6.

CookieManager


を定義する

新しいAPIとビルダーでは、接続用に

CookieManager

を設定するのは簡単です。クライアント固有の

CookieManager

を定義するために、ビルダーメソッド

cookieManager(CookieManager cookieManager)

を使用できます。

たとえば、Cookieを許可しない

CookieManager

を定義しましょう。

HttpClient.newBuilder()
  .cookieManager(new CookieManager(null, CookiePolicy.ACCEPT__NONE))
  .build();


CookieManager

がCookieの保存を許可している場合は、

HttpClient



CookieManager

を確認して、それらにアクセスできます。

httpClient.cookieManager().get().getCookieStore()

それでは、Http APIの最後のクラスである

HttpResponse

に注目しましょう。


7.

HttpResponse

オブジェクト


HttpResponse

クラスはサーバーからの応答を表します。それは多くの有用な方法を提供します – しかし最も重要な2つは以下の通りです


  • statusCode()

    – 応答のステータスコード(type

    int

    )を返す



HttpURLConnection

クラスに有効な値が含まれています)
**

body()

– レスポンスのボディを返します(戻り型は


send()メソッドに渡されるresponse

BodyHandler__パラメータ

応答オブジェクトには、

uri()



headers()



trailers()



version()

など、他にも役立つメソッドがあります。


7.1. 応答オブジェクトの

URI


レスポンスオブジェクトのメソッド

uri()

はレスポンスを受け取った元の

URI

を返します。

リダイレクトが発生する可能性があるため、要求オブジェクトの

URI

とは異なる場合があります。

assertThat(request.uri()
  .toString(), equalTo("http://stackoverflow.com"));
assertThat(response.uri()
  .toString(), equalTo("https://stackoverflow.com/"));


7.2. 応答からのヘッダ

応答オブジェクトに対してメソッド

headers()

を呼び出すことで、応答からヘッダーを取得できます。

HttpResponse<String> response = HttpClient.newHttpClient()
  .send(request, HttpResponse.BodyHandler.asString());
HttpHeaders responseHeaders = response.headers();

戻り値の型として

HttpHeaders

オブジェクトを返します。これはHTTPヘッダーの読み取り専用ビューを表す

jdk.incubator.http

パッケージで定義された新しい型です。

ヘッダ値の検索を簡単にする便利な方法がいくつかあります。


7.3. レスポンスから予告編を取得する

HTTP応答には、応答コンテンツの後に含まれる追加のヘッダーが含まれる場合があります。これらのヘッダはトレーラヘッダと呼ばれます。


HttpResponseでメソッド

trailers()__を呼び出すことで取得できます。

HttpResponse<String> response = HttpClient.newHttpClient()
  .send(request, HttpResponse.BodyHandler.asString());
CompletableFuture<HttpHeaders> trailers = response.trailers();


trailers()

メソッドが

CompletableFuture

オブジェクトを返すことに注意してください。


7.4. 応答のバージョン

メソッド

version()

は、どのバージョンのHTTPプロトコルがサーバーとの通信に使用されたかを定義します。

HTTP/2を使いたいと定義したとしても、サーバーはHTTP/1.1を介して応答できることを忘れないでください。

サーバーが応答したバージョンは、応答で指定されています。

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .version(HttpClient.Version.HTTP__2)
  .GET()
  .build();
HttpResponse<String> response = HttpClient.newHttpClient()
  .send(request, HttpResponse.BodyHandler.asString());
assertThat(response.version(), equalTo(HttpClient.Version.HTTP__1__1));


8結論

この記事では、多くの柔軟性と強力な機能を提供するJava 9の

HttpClient

APIを調べました。

いつものように、完全なコードはhttps://github.com/eugenp/tutorials/tree/master/core-java-9[GitHubに追加]を見つけることができます。

注:例では、以下によって提供されるサンプルRESTエンドポイントを使用しました。


https://postman-echo.com

.