Kotlin java.net.http.HttpClientによる非同期通信
webサーバーのリソースを非同期で取得する手法6.2 HTTPによるアプリケーション連携(RESTサービス、HTTPクライアントAPI、非同期呼び出しなど)~Java Advanced編
6.2.4 HTTPクライアントの作成方法(2):非同期型
こちらで紹介されている方法が面白そうだったので、Kotlinで試してみます。
簡単なサンプル
Javaで紹介されているサンプルを素直にKotlinで実装した結果がこちら。
- package org.example
- import java.net.URI
- import java.net.http.HttpClient // HTTPクライアントを表すクラス
- import java.net.http.HttpRequest // リクエストを表すクラス
- import java.net.http.HttpResponse // レスポンスを表すクラス
- import java.net.http.HttpHeaders // HTTPヘッダを表すクラス
- fun main() {
- // 手順1:HttpClientオブジェクトを生成する
- var client = HttpClient.newBuilder()
- .version(HttpClient.Version.HTTP_2)
- .build()
- // 手順2:HttpRequestオブジェクトを生成する
- var request = HttpRequest.newBuilder()
- .uri(URI.create("https://www.example.com/"))
- .header("User-Agent", "Java SE HttpClient")
- .build();
- // 手順3:HttpRequestを送信し、HTTPサーバーを非同期で呼び出す
- var future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
- // 手順4:後から何らかの方法でHttpResponseを取得し、何らかの後処理を行う
- var response = future.get()
- println(response.body())
- }
実行すると、https://www.example.com/のhtmlが表示されます。
これはお手軽なんじゃないでしょうか。
続いて、thenAcceptによるレスポンスの取得を試してみると、
- package org.example
- import java.net.URI
- import java.net.http.HttpClient // HTTPクライアントを表すクラス
- import java.net.http.HttpRequest // リクエストを表すクラス
- import java.net.http.HttpResponse // レスポンスを表すクラス
- import java.net.http.HttpHeaders // HTTPヘッダを表すクラス
- fun main() {
- var client = HttpClient.newBuilder()
- .version(HttpClient.Version.HTTP_2)
- .build()
- var request = HttpRequest.newBuilder()
- .uri(URI.create("https://www.example.com/"))
- .header("User-Agent", "Java SE HttpClient")
- .build();
- client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
- .thenAccept({
- println("--- get response ---")
- var resBody = it.body();
- println(resBody)
- })
- println("--- fin ---")
- }
環境にもよると思いますが、htmlは表示されずfinのみ表示されます。
取得前にメインスレッドが終了するからですね。
Thread.sleepでちょっと待ってみます。
- package org.example
- import java.net.URI
- import java.net.http.HttpClient // HTTPクライアントを表すクラス
- import java.net.http.HttpRequest // リクエストを表すクラス
- import java.net.http.HttpResponse // レスポンスを表すクラス
- import java.net.http.HttpHeaders // HTTPヘッダを表すクラス
- fun main() {
- var client = HttpClient.newBuilder()
- .version(HttpClient.Version.HTTP_2)
- .build()
- var request = HttpRequest.newBuilder()
- .uri(URI.create("https://www.example.com/"))
- .header("User-Agent", "Java SE HttpClient")
- .build();
- client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
- .thenAccept({
- println("--- get response ---")
- var resBody = it.body();
- println(resBody)
- })
- // ちょっと待つ
- Thread.sleep(1000)
- println("--- fin ---")
- }
これで取得結果が表示できました。
パラメーター付きGET
パラメーターを付けてGETを試してみます。
後にPOSTも試したいのでサーバーにこんなphpファイルをおいておきました。
- <?php
- echo ('GET'.PHP_EOL);
- var_dump($_GET);
- echo (PHP_EOL);
- echo ('POST'.PHP_EOL);
- var_dump($_POST);
- echo (PHP_EOL);
GETテスト
- ackage org.example
- import java.net.URI
- import java.net.http.HttpClient // HTTPクライアントを表すクラス
- import java.net.http.HttpRequest // リクエストを表すクラス
- import java.net.http.HttpResponse // レスポンスを表すクラス
- import java.net.http.HttpHeaders // HTTPヘッダを表すクラス
- fun main() {
- var client = HttpClient.newBuilder()
- .version(HttpClient.Version.HTTP_2)
- .build()
- var request = HttpRequest.newBuilder()
- .uri(URI.create("http://192.168.11.200/test.php?name=symfo"))
- .header("User-Agent", "Java SE HttpClient")
- .build();
- var future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
- var response = future.get()
- println(response.body())
- }
実行結果
GET
array(1) {
["name"]=>
string(5) "symfo"
}
POST
array(0) {
}
問題ないですね。
POST送信
POSTも試してみます。
- package org.example
- import java.net.URI
- import java.net.http.HttpClient // HTTPクライアントを表すクラス
- import java.net.http.HttpRequest // リクエストを表すクラス
- import java.net.http.HttpResponse // レスポンスを表すクラス
- import java.net.http.HttpHeaders // HTTPヘッダを表すクラス
- fun main() {
- var client = HttpClient.newBuilder()
- .version(HttpClient.Version.HTTP_2)
- .build()
- var request = HttpRequest.newBuilder()
- .uri(URI.create("http://192.168.11.200/test.php"))
- .header("User-Agent", "Java SE HttpClient")
- .header("Content-Type", "application/x-www-form-urlencoded")
- .POST(HttpRequest.BodyPublishers.ofString("name=symfo"))
- .build();
- var future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
- var response = future.get()
- println(response.body())
- }
こちらも狙い通りの実行結果です。
GET
array(0) {
}
POST
array(1) {
["name"]=>
string(5) "symfo"
}
JSON
JSONな文字列をPOSTしてみます。
こちらが参考になりました。
【Java】HttpClientでコンテンツ取得
サーバー側のPHPファイルを変更します。
- <?php
- var_dump(json_decode(file_get_contents('php://input')));
送信側のプログラムはこうなりました。
- package org.example
- import java.net.URI
- import java.net.http.HttpClient // HTTPクライアントを表すクラス
- import java.net.http.HttpRequest // リクエストを表すクラス
- import java.net.http.HttpResponse // レスポンスを表すクラス
- import java.net.http.HttpHeaders // HTTPヘッダを表すクラス
- fun main() {
- var client = HttpClient.newBuilder()
- .version(HttpClient.Version.HTTP_2)
- .build()
- var request = HttpRequest.newBuilder()
- .uri(URI.create("http://192.168.11.200/test.php"))
- .header("User-Agent", "Java SE HttpClient")
- .header("Content-Type", "application/json")
- .POST(HttpRequest.BodyPublishers.ofString("""{"name":"Symfo"}"""))
- .build();
- var future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
- var response = future.get()
- println(response.body())
- }
実行結果
object(stdClass)#1 (1) {
["name"]=>
string(5) "Symfo"
}
バイナリファイルの取得
画像などのバイナリファイルを取得する場合の例です。
こちらが参考になります。
クラスHttpResponse.BodyHandlers
直接ファイルとして取得する場合は、
HttpResponse.BodyHandlers.ofFile
が便利です。
- package org.example
- import java.nio.file.Files
- import java.nio.file.Path;
- import java.nio.file.Paths;
- import java.net.URI
- import java.net.http.HttpClient // HTTPクライアントを表すクラス
- import java.net.http.HttpRequest // リクエストを表すクラス
- import java.net.http.HttpResponse // レスポンスを表すクラス
- import java.net.http.HttpHeaders // HTTPヘッダを表すクラス
- fun main() {
- var client = HttpClient.newBuilder()
- .version(HttpClient.Version.HTTP_2)
- .build()
- var request = HttpRequest.newBuilder()
- .uri(URI.create("http://192.168.11.200/miku.jpg"))
- .header("User-Agent", "Java SE HttpClient")
- .build();
- var future = client.sendAsync(request, HttpResponse.BodyHandlers.ofFile(
- Paths.get("miku.jpg")
- ))
- var response = future.get()
- println(response)
- }
バイナリデータを加工に使用したい場合は、ofInputStreamを指定し、
InputStreamとして取得します。
- package org.example
- import java.nio.file.Files
- import java.nio.file.Path;
- import java.nio.file.Paths;
- import java.net.URI
- import java.net.http.HttpClient // HTTPクライアントを表すクラス
- import java.net.http.HttpRequest // リクエストを表すクラス
- import java.net.http.HttpResponse // レスポンスを表すクラス
- import java.net.http.HttpHeaders // HTTPヘッダを表すクラス
- fun main() {
- var client = HttpClient.newBuilder()
- .version(HttpClient.Version.HTTP_2)
- .build()
- var request = HttpRequest.newBuilder()
- .uri(URI.create("http://192.168.11.200/miku.jpg"))
- .header("User-Agent", "Java SE HttpClient")
- .build();
- var future = client.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream())
- var response = future.get()
- runCatching {
- // InputStreamをファイルに出力
- var f = Files.copy(response.body(), Paths.get("miku.jpg"))
- }
- }
バイナリファイルのアップロード
こちらが参考になりました。
クラスHttpRequest.BodyPublishers
ファイルを直接指定する場合は
BodyPublishers.ofFile
が便利です。
- package org.example
- import java.nio.file.Files
- import java.nio.file.Path;
- import java.nio.file.Paths;
- import java.net.URI
- import java.net.http.HttpClient // HTTPクライアントを表すクラス
- import java.net.http.HttpRequest // リクエストを表すクラス
- import java.net.http.HttpResponse // レスポンスを表すクラス
- import java.net.http.HttpHeaders // HTTPヘッダを表すクラス
- fun main() {
- var client = HttpClient.newBuilder()
- .version(HttpClient.Version.HTTP_2)
- .build()
- var request = HttpRequest.newBuilder()
- .uri(URI.create("http://192.168.11.200/test.php"))
- .header("User-Agent", "Java SE HttpClient")
- .POST(HttpRequest.BodyPublishers.ofFile(Paths.get("miku.jpg")))
- .build();
- var future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
- var response = future.get()
- println(response.body())
- }
バイト配列を指定する場合
- package org.example
- import java.io.File
- import java.nio.file.Path;
- import java.nio.file.Paths;
- import java.net.URI
- import java.net.http.HttpClient // HTTPクライアントを表すクラス
- import java.net.http.HttpRequest // リクエストを表すクラス
- import java.net.http.HttpResponse // レスポンスを表すクラス
- import java.net.http.HttpHeaders // HTTPヘッダを表すクラス
- fun main() {
- var uploadBin = File("miku.jpg").readBytes()
- var client = HttpClient.newBuilder()
- .version(HttpClient.Version.HTTP_2)
- .build()
- var request = HttpRequest.newBuilder()
- .uri(URI.create("http://192.168.11.200/test.php"))
- .header("User-Agent", "Java SE HttpClient")
- .POST(HttpRequest.BodyPublishers.ofByteArray(uploadBin))
- .build();
- var future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
- var response = future.get()
- println(response.body())
- }
コメント