HTTP Client APIの多様な利用方法
簡単なリクエスト処理の実行であれば前回紹介した内容だけでほとんどカバーできると思いますが、HTTP2やWebSocket等での機能を求める理由として、リアルタイム性が高い機能が望まれる場合が多くあります。
その場合には、リクエスト処理と受信したデータの処理を同期的に処理することが少なくなり、APIを実行する際にもより高度な利用方法が求められます。そして、サーバに接続する際にも、接続条件が必要になるケースもあります。
そこで、いくつかのパターンの利用方法を紹介し、新しいHTTP Client APIをどのように利用できるかを紹介します。
接続方法のカスタマイズとBasic認証などへの対応
前回は、HTTP Clientのオブジェクトを作成する際にはデフォルトの設定で作成するnewHttpClientメソッドを使っていましたが、表1のメソッドを使って接続をカスタマイズすることができます。
| メソッド | 概要 |
|---|---|
| authenticator(Authenticator authenticator) | 認証方法を設定する。Basic認証など必要な場合に利用する |
| connectTimeout(Duration duration) | 接続タイムアウトを設定する |
| cookieHandler(CookieHandler cookieHandler) | Cookie処理方法を設定する |
| executor(Executor executor) | 並列実行のためのExecutorクラスを設定する |
| followRedirects | リダイレクトの許可・不許可のポリシーを設定する |
| priority(int priority) | HTTP2でリクエストする際のデフォルトプライオリティを設定する |
| proxy(ProxySelector proxySelector) | 接続時に利用するプロキシがある場合の設定をする |
| sslContext(SSLContext sslContext) | SSL/TLS接続時の設定をする |
| version(HttpClient.Version version) | HTTPのバージョン(1.1もしくは2)を指定する |
リスト1では、Basic認証を使う場合と、開発においてよくある、自己署名証明書を使ったSSL接続の例を示します。
HttpClient client = HttpClient.newBuilder()
.authenticator(new BasicAuthenticator("hoge","pswd")) // (1) Basic認証を設定する
.sslContext(this.createSSLContext()) // (2) 指定したSSLContextを使う場合
.build();
// 省略
// (3) Basic認証を行うクラス
private class BasicAuthenticator extends Authenticator{
private String username;
private String password;
private BasicAuthenticator(String username,String password){
this.username = username;
this.password = password;
}
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username,password.toCharArray());
}
}
// (4) 自己署名証明書を受け入れるためのSSLContextの作成
private SSLContext createSSLContext() throws Exception{
// org.apache.http.ssl.SSLContextBuilderを使っている
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
return builder.build();
}
(1)は認証方法の設定をします。認証方法はjava.net.Authenticatorクラスのサブクラスを実装したもの(3)を設定します。
Basic認証が必要になると、自動的にgetPasswordAuthentication()メソッドがコールされます。つまりパスワードを間違えると再度、パスワードが求められるのでgetPasswordAuthentication()も再度コールされ、最大3回までリトライされます。
この流れは、UIを伴いパスワードを別で管理している場合には適していますが、例に示すようにあらかじめパスワードがわかっている場合にはリクエスト時にヘッダに設定してしまった方がよいでしょう。
また、SSLの自己証明書での接続エラーも開発時によく発生する問題です。その場合には、(2)のようにSSLContextのインスタンスを設定し、回避することができます。
今回のサンプルではSSLContextのインスタンスを(4)のようにApache HttpComponentsのAPIを使って作成しています。
非同期での複数リクエスト
続いて、複数のリクエストを非同期で処理し、すべての結果が取得可能になり次第それらのデータ処理する場合のコードをリスト2に示します。
HttpClient client = HttpClient.newHttpClient();
// (1) リクエストするメソッドの作成
HttpRequest getRequest1 = HttpRequest.newBuilder().uri(URI.create("http://localhost/req1.php")).build();
HttpRequest getRequest2 = HttpRequest.newBuilder().uri(URI.create("http://localhost/req2.php")).build();
// (2) 非同期でのリクエストの実行
CompletableFuture<HttpResponse<String>> f1 =
client.sendAsync(getRequest1,HttpResponse.BodyHandlers.ofString());
CompletableFuture<HttpResponse<String>> f2 =
client.sendAsync(getRequest2,HttpResponse.BodyHandlers.ofString());
try {
// (3) 複数のリクエストを待つ
CompletableFuture<Void> ff = CompletableFuture.allOf(f1,f2);
ff.join();
HttpResponse<String> response1 = f1.get();
HttpResponse<String> response2 = f2.get();
}
catch(Exception ex){
// (4) いずれかのリクエストがエラーになった場合
}
(1)ではリクエストするためのオブジェクトを作成します。次に、(2)のようにそれらのリクエストを非同期で実行します。
それぞれのリクエストの結果はCompletableFutureのインスタンスとして取得できるので、(3)のようにallOfメソッドを使えば、すべての結果を待つコードも簡単に記述できます。
そして、いずれかのリクエストでエラーが発生した場合でも、エラーは(4)のように1カ所で記述でき、エラー処理も非常に簡単です。
