Java9 HttpClient インキュベーターなので、この先どうなるか判らないが、
Apatch HTTPClient を使わなくて済むようになるのか?
とりあえず試してみる。
モジュール使用宣言を用意する必要があり、module-info..java を次のように用意する。
module sample{ requires jdk.incubator.httpclient; }
パッケージは、jdk.incubator.http だが、requires で書くのは、jdk.incubator.httpclient
import するもの
import java.net.URI; import java.nio.charset.StandardCharsets; import jdk.incubator.http.HttpClient; import jdk.incubator.http.HttpRequest; import jdk.incubator.http.HttpResponse;
まずは、同期型
try{ HttpRequest request = HttpRequest.newBuilder(URI.create("http://www.google.com")) .GET() .build(); HttpResponse<String> res = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1) .followRedirects(HttpClient.Redirect.SAME_PROTOCOL).build() .send(request, HttpResponse.BodyHandler.asString(StandardCharsets.UTF_8)); // HttpResponse を参照 res.headers().map().entrySet().forEach(e->{ System.out.println(e.getKey() + "→" + e.getValue() ); }); System.out.println(res.body()); }catch(Exception e){ e.printStackTrace(); }
非同期型は、sendAsync を使う、HttpResponse.BodyHandler
HttpRequest request = HttpRequest.newBuilder(URI.create("http://www.google.com")) .GET() .build(); CompletableFuture<HttpResponse<String>> future = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1) .followRedirects(HttpClient.Redirect.SAME_PROTOCOL).build() .sendAsync(request, HttpResponse.BodyHandler.asString(StandardCharsets.UTF_8)); // CompletableFuture<HttpResponse<String>> を join する。 future.handle((r, t)->{ System.out.println(Thread.currentThread().getName()); r.headers().map().entrySet().forEach(e->{ System.out.println(e + "→" + e.getValue() ); }); System.out.println(r.body()); return r; }).join();
ExecutorService handleAsync で、、、
final ExecutorService service = Executors.newFixedThreadPool(4); HttpRequest request = HttpRequest.newBuilder(URI.create("http://www.google.com")) .GET() .build(); HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1) .followRedirects(HttpClient.Redirect.SAME_PROTOCOL) .executor(service) .build() .sendAsync(request, HttpResponse.BodyHandler.asString(StandardCharsets.UTF_8)) .handleAsync((r, t)->{ System.out.println(Thread.currentThread().getName()); r.headers().map().entrySet().forEach(e->{ System.out.println(e + "→" + e.getValue() ); }); System.out.println(r.body()); return r; }).join(); service.shutdown();
同じリクエスト、ExecutorService whenCompleteAsync で、例外発生時も捕捉する場合
final ExecutorService service = Executors.newFixedThreadPool(4); HttpRequest request = HttpRequest.newBuilder(URI.create("http://www.google.com")) .GET() .build(); HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1) .followRedirects(HttpClient.Redirect.SAME_PROTOCOL) .executor(service) .build() .sendAsync(request, HttpResponse.BodyHandler.asString(StandardCharsets.UTF_8)) .whenCompleteAsync((r, x)->{ r.headers().map().entrySet().forEach(e->{ System.out.println(e + "→" + e.getValue() ); }); System.out.println(r.body()); Optional.ofNullable(x).ifPresent(t->t.printStackTrace()); }).join();
これは、java.util.concurrent.CompletionException でラップされた例外を捕捉することになる。
URL が誤ってれば、java.nio.channels.UnresolvedAddressExceptionなどがラップされて捕捉される。
サンプルとしてもっと簡単に、返されるレスポンス BODYだけを標準出力するなら、、、
HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1) .followRedirects(HttpClient.Redirect.SAME_PROTOCOL) .executor(service) .build() .sendAsync(request, HttpResponse.BodyHandler.asString(StandardCharsets.UTF_8)) .thenApply(HttpResponse::body) .thenAccept(System.out::println) .join();
結果 body をファイル出力するなら。 HttpResponse.BodyHandler.asFile を使う。
HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1) .followRedirects(HttpClient.Redirect.SAME_PROTOCOL) .executor(service) .build() .sendAsync(request, HttpResponse.BodyHandler.asFile(FileSystems.getDefault().getPath("c:/work/test"))) .thenApply(HttpResponse::body) //.thenAccept(System.out::println) /* ファイル出力した時の path を標準出力 */ .join();
↑ //.thenAccept(System.out::println) は、ファイル出力もするけど、標準出力もするようにもできる。