ダウンロード サンプルファイル (3.7 KB)
HTTP Client API
HTTP Client APIの追加はもっとも多くの開発者にとって影響があると思われます。
Java 9がリリースされる前にはHTTP2 Clientといった触れ込みでリリースされる予定がありましたが、Java 11までに完全に実装が書き換わり、Java 11ではHTTP2のみならず、HTTP関連のプロトコルを扱うためのClient APIとしてリリースされました。
また、Javaで、HTTP Clientとしての機能を使う場合には標準で用意されているHttpURLConnectionクラスを利用するか、Apache HttpClientやOkHttpなどの外部ライブラリを利用するケースが多いと思います。
しかし、HTTP Client APIはこれまでのHttpURLConnectionよりも使いやすく、また、多くのケースでは外部ライブラリを使わなくてもよいレベルになるはずです。
特に、HttpURLConnectionに比べて、以下のメリットがあります。
- HTTP 1.1だけではなく、HTTP 2にも対応している
- 同期処理だけでなく、Non-Blockingでの非同期処理にも対応している
- 外部APIを使っていた方でもわかりやすく、よりなりじみやすいAPI構造
- WebSocket通信も可能
基本的なAPIの使い方
最初に、APIの利用方法をイメージするため、基本的なHTTP GET/POSTの利用方法を紹介します。
リスト5は同期処理としてHTTP GETでHTMLテキストを取得する場合の実行例です。(1)でHTTP Clientのオブジェクトを作成し、(2)でリクエストを作成、(3)でリクエストを実行といった流れになっています。
HttpClient client = HttpClient.newHttpClient(); // (1) HTTP Clientを作成
HttpRequest getRequest = HttpRequest.newBuilder()
.uri(URI.create("https://codezine.jp/"))
.build(); // (2) リクエストを作成
HttpResponse<String> response = client.send(getRequest, HttpResponse.BodyHandlers.ofString()); // (3) レスポンスを取得する
logger.log(Level.INFO,response.body());
HttpURLConnectionなどを使った処理よりも、HTTP操作としては自然なコーディングスタイルとして利用できることがわかるはずです。
また、リスト6はApache HTTP Clientを使った場合のHTTP GETメソッドを使った処理のコード例ですが、同様な流れで記述できることがわかります。
従って、リプレースなどもしやすいはずです。
CloseableHttpClient client = HttpClients.createDefault(); // HTTP Clientを作成
HttpGet requestGet = new HttpGet("http://localhost/get.php"); // (2) リクエストを作成
CloseableHttpResponse response = client.execute(requestGet); // (3) レスポンスを取得する
logger.log(System.Logger.Level.INFO,EntityUtils.toString(response.getEntity()));
response.close();
続いて、非同期処理の場合のコード例をリスト7に示します。
非同期処理ではHttpResponseの代わりに、(1)のように非同期でリクエストを実行すると、戻り値としてCompletableFutureが返って来ます。
CompletableFutureはJava1.8から導入された、比較的新しいAPIです。CompletableFutureクラスの使い方は今回説明しませんが、Futureインターフェースの実装クラスで複数の非同期処理が管理しやすくなります。
レスポンスに対する処理は(2)のようにCompletableFutureクラスのthenAcceptメソッドなどを利用し処理を行うことができます。
HttpClient client = HttpClient.newHttpClient();
HttpRequest getRequest = HttpRequest.newBuilder()
.uri(URI.create("http://localhost/get.php"))
.build();
CompletableFuture<Void> f = client.sendAsync(getRequest,HttpResponse.BodyHandlers.ofString()) // (1) 非同期リクエストの実行
.thenAccept(response -> { // (2) レスポンスに対する処理
logger.log(Level.INFO,"status code : " + response.statusCode());
logger.log(Level.INFO,"body is : " + response.body());
});
続いて、JSONデータをPOST処理する場合の例をリスト8に示します。(1)でPOSTするJSONデータを作成します。そして、(2)でJSONデータのコンテントタイプをヘッダにて指定し、(3)にてPOSTメソッドで送信するJSONデータを指定します。
今までの例では、(3)のように明示的にPOSTメソッドを指定していませんでしたが、これはデフォルトでGETメソッドが指定されるためです。
HttpClient client = HttpClient.newHttpClient();
String json = "{ \"key\" : \"value\" }"; // (1) POSTするJSONデータ
HttpRequest postRequest = HttpRequest.newBuilder()
.header("Content-Type","application/json") // (2) ヘッダの指定
.uri(URI.create("http://localhost/post.php"))
.POST(HttpRequest.BodyPublishers.ofString(json)) // (3) POSTメソッドを指定
.build();
HttpResponse<String> response = client.send(postRequest, HttpResponse.BodyHandlers.ofString());
logger.log(Level.INFO,response.body());
リクエストボディとレスポンスボディの型指定
これまで紹介したコードを見ると、sendもしくはsendAsyncメソッドでHttpResponse.BodyHandlersというクラスを使用しています。
また、POSTメソッドではHttpRequest.BodyPublishersというクラスを使用しています。
HTTP Client APIでは、レスポンスボディの形式をHttpResponse.BodyHandlerインターフェースを使って処理します。
そして、HttpResponse.BodyHandlersには表1のように、よく利用するであろう実装があらかじめ用意されています。
また、ここで紹介するメソッド以外にも用意されているので、詳細はAPIリファレンスを参照してください。
| レスポンスボディの型 | メソッド | 概要 |
|---|---|---|
| Void | discarding() | レスポンスボディを取得しない場合 |
| byte[] | ofByteArray() | byte配列として取得する場合 |
| String | ofString() | 文字列として取得する場合 |
| Stream<String> | ofLines() | Stream<String>(1行ごとを文字列)として取得する場合 |
| InputStream | ofInputStream() | InputStreamとして取得する場合 |
| Path | ofFile(Path file) | 指定したファイルにデータを保存して取得する場合 |
| Path | ofFileDownload(Path directory, OpenOption... openOptions) | 指定したフォルダにContent-Dispositionヘッダで指定されたファイル名でデータを保存して取得する場合 |
リクエストボディの形式は、HttpRequest.BodyPublisherインターフェースを使って処理します。
こちらも、HttpRequest.BodyPublishersに、表2のようにあらかじめよく利用すると思われる実装が用意されています。
| 指定するリクエストボディの型 | メソッド | 概要 |
|---|---|---|
| void | noBody() | 空のリクエストボディを指定する場合 |
| byte[] | ofByteArray(byte[] buf) | byte配列データを指定する場合 |
| String | ofString(String body) | 文字列データを指定する場合 |
| InputStream | ofInputStream(Supplier<? extends InputStream> streamSupplier) | 指定したファイルのデータを指定する場合 |
| Path | ofFile(Path file) | InputStreamとして取得する場合 |
リクエストボディとレスポンスボディの処理は内部で、Java 9から導入されたリアクティブ・ストリームのFlow.PublisherやFlow.SubscriberなどのAPIを利用しています。
従って、単純なHTTP操作ではなく、少々複雑なChunk処理や、WebSocketのようなHTTPプロトコル内で動作するプロトコルなどの処理もしやすくなるはずです。
最後に
Java 11はLTS版の位置付けになっているので、開発者にとってもJavaサポートバージョンの1つの区切りとして意識する必要があると言えます。そのバージョンでJava EE関連のモジュールが削除されたことは、Javaとしての1つの方向性を示しているでしょう。
また、HTTP Client APIの追加は、多くの開発者が興味を持つ変更だと思われます。現在の開発ではWebサービスと連携して機能を開発することは必須とも言え、こういったAPIが今導入されることはむしろ遅かったとも思います。
今回のHTTP Client APIの紹介は簡単な利用例のみでしたが、次回はWebSocket通信を含めてより実用的な利用方法などを紹介します。
参考資料
この記事は参考になりましたか?
既に会員の方はを行ってください。
- Java 11の変更点と新しいAPI連載記事一覧
-
- HTTP Client APIでの接続カスタマイズからWebSocketでの接続まで行う
- Java 11の変更点を押さえよう! 標準機能になったHTTP Client API
- この記事の著者
-
WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)
< WINGSプロジェクト について> 有限会社 WINGSプロジェクト が運営する、テクニカル執筆コミュニティ(代表 ...
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
-
山田 祥寛(ヤマダ ヨシヒロ)
静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数。
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この記事は参考になりましたか?
この記事をシェア
