1. 概要

Java HttpClientAPIはJava11で導入されました。 API は、最新のHTTP標準のクライアント側を実装します。 同期および非同期プログラミングモデルの両方で、HTTP/1.1およびHTTP/2をサポートします。

これを使用して、HTTPリクエストを送信し、それらのレスポンスを取得できます。 Java 11より前は、基本的なURLConnection実装またはApacheHttpClientなどのサードパーティライブラリに依存する必要がありました。

このチュートリアルでは、Java HttpClientを使用したPOSTリクエストの送信について説明します。 同期POSTリクエストと非同期POSTリクエストの両方、および同時POSTリクエストを送信する方法を示します。 さらに、認証パラメーターとJSON本文をPOSTリクエストに追加する方法を確認します。

最後に、ファイルをアップロードしてフォームデータを送信する方法を説明します。 したがって、一般的なユースケースのほとんどを取り上げます。

2. POSTリクエストの準備

HTTPリクエストを送信する前に、まずHttpClientのインスタンスを作成する必要があります。

HttpClientインスタンスは、 newBuilder メソッドを使用して、ビルダーから構成および作成できます。 それ以外の場合、構成が必要ない場合は、newHttpClientユーティリティメソッドを使用してデフォルトのクライアントを作成できます。

HttpClient client = HttpClient.newHttpClient();

HttpClientはデフォルトでHTTP/2を使用します。 また、サーバーがHTTP / 2をサポートしていない場合は、HTTP/1.1に自動的にダウングレードされます。

これで、ビルダーからHttpRequestのインスタンスを作成する準備が整いました。 後でこのリクエストを送信するためにクライアントインスタンスを利用します。 POSTリクエストの最小パラメータは、サーバーURL、リクエストメソッド、および本文です。

HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create(serviceUrl))
  .POST(HttpRequest.BodyPublishers.noBody())
  .build();

リクエスト本文は、BodyPublisherクラスを介して提供する必要があります。 これは、リクエスト本文のストリームをオンデマンドで公開するリアクティブストリームパブリッシャーです。 この例では、リクエストボディを送信しないボディパブリッシャーを使用しました。

3. POSTリクエストの送信

POSTリクエストを準備したので、それを送信するためのさまざまなオプションを見てみましょう。

3.1. 同期的に

このデフォルトのsendメソッドを使用して、準備されたリクエストを送信できます。 このメソッドは、応答が受信されるまでコードをブロックします

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString())

BodyHandlers ユーティリティは、応答本文を String として処理したり、応答本文をファイルにストリーミングしたりするなど、さまざまな便利なハンドラーを実装します。 応答が受信されると、 HttpResponse オブジェクトには、応答ステータス、ヘッダー、および本文が含まれます。

assertThat(response.statusCode())
  .isEqualTo(200);
assertThat(response.body())
  .isEqualTo("{\"message\":\"ok\"}");

3.2. 非同期

sendAsync メソッドを使用して、前の例と同じリクエストを非同期で送信できます。 このメソッドは、コードをブロックする代わりに、 CompleteableFuture instanceをすぐに返します。

CompletableFuture<HttpResponse<String>> futureResponse = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());

CompleteableFuture は、利用可能になるとHttpResponseで完了します。

HttpResponse<String> response = futureResponse.get();
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.body()).isEqualTo("{\"message\":\"ok\"}");

3.3. 同時に

StreamsCompletableFuturesを組み合わせて、複数のリクエストを同時に発行し、それらの応答を待つことができます

List<CompletableFuture<HttpResponse<String>>> completableFutures = serviceUrls.stream()
  .map(URI::create)
  .map(HttpRequest::newBuilder)
  .map(builder -> builder.POST(HttpRequest.BodyPublishers.noBody()))
  .map(HttpRequest.Builder::build)
  .map(request -> client.sendAsync(request, HttpResponse.BodyHandlers.ofString()))
  .collect(Collectors.toList());

それでは、すべてのリクエストが完了するのを待って、それらのレスポンスを一度に処理できるようにします。

CompletableFuture<List<HttpResponse<String>>> combinedFutures = CompletableFuture
  .allOf(completableFutures.toArray(new CompletableFuture[0]))
  .thenApply(future ->
    completableFutures.stream()
      .map(CompletableFuture::join)
      .collect(Collectors.toList()));

allOfメソッドとjoinメソッドを使用してすべての応答を結合すると、応答を保持する新しいCompleteableFutureが得られます。

List<HttpResponse<String>> responses = combinedFutures.get();
responses.forEach((response) -> {
  assertThat(response.statusCode()).isEqualTo(200);
  assertThat(response.body()).isEqualTo("{\"message\":\"ok\"}");
});

4. 認証パラメータの追加

すべてのリクエストでHTTP認証を行うためにクライアントレベルでオーセンティケーターを設定できます

HttpClient client = HttpClient.newBuilder()
  .authenticator(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
      return new PasswordAuthentication(
        "baeldung",
        "123456".toCharArray());
      }
  })
  .build();

ただし、 HttpClient は、サーバーから WWW-Authenticate ヘッダーでチャレンジされるまで、基本的な資格情報を送信しません。

これを回避するために、基本認証ヘッダーをいつでも手動で作成して送信できます。

HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create(serviceUrl))
  .POST(HttpRequest.BodyPublishers.noBody())
  .header("Authorization", "Basic " + 
    Base64.getEncoder().encodeToString(("baeldung:123456").getBytes()))
  .build();

5. ボディの追加

これまでの例では、POSTリクエストに本文を追加していません。 ただし、POSTメソッドは通常、リクエスト本文を介してサーバーにデータを送信するために使用されます。

5.1. JSON本文

BodyPublishers ユーティリティは、 String またはファイルからのリクエスト本文の公開など、さまざまな便利なパブリッシャーを実装します。 JSONデータを文字列として公開し、UTF-8文字セットを使用して変換できます。

HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create(serviceUrl))
  .POST(HttpRequest.BodyPublishers.ofString("{\"action\":\"hello\"}"))
  .build();

5.2. ファイルのアップロード

HttpClientを介したアップロードに使用できる一時ファイルを作成しましょう。

Path file = tempDir.resolve("temp.txt");
List<String> lines = Arrays.asList("1", "2", "3");
Files.write(file, lines);

HttpClientは、POST本体にファイルを追加するための別のメソッドBodyPublishers.ofFileを提供します。 一時ファイルをメソッドパラメーターとして追加するだけで、残りはAPIが処理します。

HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create(serviceUrl))
  .POST(HttpRequest.BodyPublishers.ofFile(file))
  .build();

5.3. フォームの送信

ファイルとは異なり、HttpClientはフォームデータを投稿するための個別の方法を提供していません。 したがって、BodyPublishers.ofStringメソッド使用する必要があります。

Map<String, String> formData = new HashMap<>();
formData.put("username", "baeldung");
formData.put("message", "hello");

HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create(serviceUrl))
  .POST(HttpRequest.BodyPublishers.ofString(getFormDataAsString(formData)))
  .build();

ただし、カスタム実装を使用して、フォームデータをMapからStringに変換する必要があります。

private static String getFormDataAsString(Map<String, String> formData) {
    StringBuilder formBodyBuilder = new StringBuilder();
    for (Map.Entry<String, String> singleEntry : formData.entrySet()) {
        if (formBodyBuilder.length() > 0) {
            formBodyBuilder.append("&");
        }
        formBodyBuilder.append(URLEncoder.encode(singleEntry.getKey(), StandardCharsets.UTF_8));
        formBodyBuilder.append("=");
        formBodyBuilder.append(URLEncoder.encode(singleEntry.getValue(), StandardCharsets.UTF_8));
    }
    return formBodyBuilder.toString();
}

6. 結論

この記事では、 we は、Java11で導入されたJavaHttpClientAPIを使用したPOSTリクエストの送信について説明しました。

HttpClient インスタンスを作成し、POSTリクエストを準備する方法を学びました。 準備されたリクエストを同期、非同期、および同時に送信する方法を見ました。 次に、基本認証パラメーターを追加する方法についても説明しました。

最後に、POSTリクエストに本文を追加する方法について説明しました。 JSONペイロード、ファイルのアップロード、フォームデータの送信について説明しました。

いつものように、完全なソースコードはGitHubから入手できます。