【Java】Java11でのHTTPリクエスト

2019年7月1日

JavaでHTTPリクエストをしたい場合HttpURLConnectionクラスを使うと簡単に処理できますが、Java11からはHttpClientなどjava.net.httpパッケージのクラスが使用できるようになりました。

今回は、この新しく追加されたjava.net.httpパッケージのクラスでHTTPリクエストを実行していってみましょう。



使用するクラス群

HttpClient

HTTPリクエストの処理を行うクラスです。
send(HttpRequest,BodyHandler)メソッドでHTTPリクエストを送信します。
戻り値はHttpResponseです。

HttpRequest

HTTPリクエストの送信内容を設定するクラスです。

HttpRequest.BodyPublisher

HTTPリクエストbodyを作成するクラスです。

HttpResponse

HTTPレスポンスの内容が集約されたクラスです。

HttpResponse.BodyHandler

HTTPレスポンスbodyを取得するためのクラスです。

HTTPリクエストサンプル

試しにgoogleの検索ページを取得するリクエストを送信してみましょう。

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandler;
import java.nio.charset.StandardCharsets;

public class TestClient2 {

	public static void main(String[] args) {
		try {
			HttpRequest request = HttpRequest
					.newBuilder(URI.create("http://google.com"))
					.build();

			BodyHandler<String> bodyHandler = HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8);
			HttpResponse<String> response = HttpClient.newBuilder().build().send(request, bodyHandler);
			System.out.println(response.body());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
実行結果

<HTML><HEAD><meta http-equiv=”content-type” content=”text/html;charset=utf-8″>
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF=”http://www.google.com/”>here</A>.
</BODY></HTML><HTML><HEAD><meta http-equiv=”content-type” content=”text/html;charset=utf-8″>
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF=”http://www.google.com/”>here</A>.
</BODY></HTML>

検索ページのHTMLが返されれば成功です。

自分でHTTPサーバーを用意してHTTPリクエストを試す

既存のサイトへリクエストを飛ばすことでもテストは可能ですが、HTTPのことをより理解するために自力でHTTPサーバーを用意して試す方法もやってみました。

サーバーも自分で用意するほうが各種メソッドの動きなどが調べやすい・・・かもしれませんよね?

ServerSocketを使用したサーバーとApacheTomcatを使用した、本番に近いサーバーを使ってみます。

ServerSocketを使用した簡易HTTPサーバーでテスト

ServerSocketでHTTPサーバーを作るのは面倒なので、ちゃんとしたレベルまでは作りません。とりあえずブラウザに表示できるとこまでを作りました。

TestServer2.java
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class TestSocketServer2 {

	public static void main(String[] args) {
		ServerSocket ss;
		try {
			ss = new ServerSocket(80);
			while(true) {
				Socket sock = ss.accept();

				InputStream is = sock.getInputStream();

				while(is.available()==0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

				byte[] readData = new byte[20000];
				is.read(readData);
				String requestData = new String(readData,StandardCharsets.UTF_8);

				if ( requestData != null && requestData.length() > 0 && requestData.indexOf("\n") != -1) {
					String[] firstHead = requestData.substring(0, requestData.indexOf("\n")).split(" ");
					String path = firstHead[1];

					System.out.println("=======リクエストデータ=======");
					System.out.println(requestData);
					System.out.println("=======リクエストデータ=======");

					OutputStream os = sock.getOutputStream();
					os.write("HTTP/1.1 200 OK\n".getBytes(StandardCharsets.UTF_8));
					os.write("Content-Type: ".getBytes(StandardCharsets.UTF_8));
					os.write("text/html; charset=UTF-8;\n".getBytes(StandardCharsets.UTF_8));

					String responseHTML = "<html><body><div style='background-color:red;color:white;'>不明なページ</div></body></html>";
					if ( path.endsWith("aaa") ) {
						responseHTML = "<html><body><div style='background-color:green;color:white;'>ああああ</div></body></html>";
					}
					byte[] responseBody = responseHTML.getBytes(StandardCharsets.UTF_8);

					os.write(("Content-Length: "+responseBody.length+"\n").getBytes(StandardCharsets.UTF_8));
					os.write(("\n").getBytes(StandardCharsets.UTF_8));
					os.write(responseBody);
					os.close();
				}
				is.close();
				sock.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

ブラウザでのアクセステスト
「localhost/何かの文字列」でアクセスできます。

表示できましたね。

それでは、HTTPリクエストの機能を使ってみましょう。

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandler;
import java.nio.charset.StandardCharsets;

public class TestClient2 {

	public static void main(String[] args) {
		try {
			HttpRequest request = HttpRequest
					.newBuilder(URI.create("http://localhost/aaa"))
					.POST(BodyPublishers.ofString("p1=きゃぷてんファルコン&p2=さすがFC"))
					.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
					.build();

			BodyHandler<String> bodyHandler = HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8);
			HttpResponse<String> response = HttpClient.newBuilder().version(Version.HTTP_1_1).build().send(request, bodyHandler);
			System.out.println(response.body());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
クライアント側の実行結果

<html><body><div style=’background-color:green;color:white;’>ああああ</div></body></html>

サーバー側の実行結果

=======リクエストデータ=======
POST /aaa HTTP/1.1
Content-Length: 48
Host: localhost
User-Agent: Java-http-client/11.0.3
Content-Type: application/x-www-form-urlencoded; charset=utf-8

p1=きゃぷてんファルコン&p2=さすがFC
=======リクエストデータ=======

ApacheTomcatを使用したHTTPサーバーでテスト

ApacheTomcat版はファイルが多少多くなるので、私がgitにアップしているテスト用のHTTPサーバープログラムを使用します。

設定方法とか、わかる方はご自由に、お使いいただいて結構です。(動的Webプロジェクトで作成したものとなります。)

TestServer2.java


import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class TestServer2 extends HttpServlet {

	protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
		try {
			process(arg0,arg1);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
		try {
			process(arg0,arg1);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	void process(HttpServletRequest req, HttpServletResponse res) throws Exception {
		System.out.println("========リクエスト処理の開始========");

		System.out.println("========受信パラメータ========");
		Map<String, String[]> map = req.getParameterMap();
		for ( Map.Entry<String, String[]> e : map.entrySet() ) {
			System.out.println(e.getKey()+"="+Arrays.toString(e.getValue()));
		}
		System.out.println("========受信パラメータ========");

		String path = req.getRequestURI();
		res.setCharacterEncoding("UTF-8");
		res.setContentType("text/html");
		PrintWriter out = res.getWriter();
		System.out.println("========レスポンスデータ作成========");
		if (path.endsWith("zugo")) {
			String html = "<html><body><div>ずごー!</div></body></html>";
			out.println(html);
			System.out.println(html);
		} else {
			String html = "<html><body><div style='background-color:red;'>不明なぺーじ</div></body></html>";
			out.println(html);
			System.out.println(html);
		}
		System.out.println("========レスポンスデータ作成========");
		System.out.println("========リクエスト処理の終了========");
	}
}

ブラウザでのアクセステスト
「localhost:8080/TestServer2/test2/何かの文字列」でアクセスできます。

うまく機能しているようです。

では、このサーバープログラムに対して下記のようなリクエストプログラムを実行して試してみましょう。

TestClient2.java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandler;
import java.nio.charset.StandardCharsets;

public class TestClient2 {

	public static void main(String[] args) {
		try {
			HttpRequest request = HttpRequest
					.newBuilder(URI.create("http://localhost:8080/TestServer2/test2/zugo"))
					.POST(BodyPublishers.ofString("p1=まりお&p2=ひげ&p3=はながでかい"))
					.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
					.build();

			BodyHandler<String> bodyHandler = HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8);
			HttpResponse<String> response = HttpClient.newBuilder().build().send(request, bodyHandler);
			System.out.println(response.body());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
クライアント側の実行結果

<html><body><div>ずごー!</div></body></html>

サーバー側の実行結果

========リクエスト処理の開始========
========受信パラメータ========
p1=[まりお]
p2=[ひげ]
p3=[はながでかい]
========受信パラメータ========
========レスポンスデータ作成========
<html><body><div>ずごー!</div></body></html>
========レスポンスデータ作成========
========リクエスト処理の終了========

予想されている動作となっているようです。

よし!これからは新しいほうをどんどん使っていくぞ!

・・・多分

Java

Posted by nompor