ネットワーク通信における低水準(low-level)と高水準(high-level)
参考: java.netパッケージ
ネットワーク通信
を行うjava.net
パッケージのAPI
は、以下の2つに分類される。
API水準 | 内容 | クラス |
---|---|---|
低水準API |
IPアドレス | ・Inet4Address ・ Inet6Address
|
ソケット | ・Socket ・ ServerSocket ・ DatagramSocket ・ MulticastSocket
|
|
インタフェース | NetworkInterface |
|
プロキシ | Proxy |
|
高水準API |
URI | URI |
URL | URL |
|
接続 | ・URLConnection ・ HttpURLConnection
|
低水準API
はOSI参照モデル
の物理層〜トランスポート層
を担っており、
高水準API
はセッション層〜アプリケーション層
を担う。
URLを用いたHTML情報の取得
参考: jsoup(外部ライブラリ)
Java標準ライブラリ
を用いてHTML情報
を取得する場合、URL
クラスのopenStream()
メソッドを用いることで、
バイトストリーム
を経由してデータを取得(=GET
)することができる。
import java.io.*;
import java.net.URL;
public class GetHTML {
public static void main(String[] args) {
URL url = null;
try {
// 「URL情報」を保持するURLオブジェクトの生成
url = new URL("http://httpbin.org/get");
} catch (Exception e) {
e.printStackTrace();
}
try (
// URLオブジェクトによるバイトストリームの生成
InputStream is = url.openStream();
// バイトストリーム -> 文字ストリーム への変換を行うInputStreamReaderフィルタの生成
InputStreamReader isr = new InputStreamReader(is);
// 「バッファリング」を行うBufferedReaderフィルタの生成
BufferedReader br = new BufferedReader(isr);
) {
// HTML情報の取得・コンソールへの出力
String html = br.readLine();
while (!(html.equals(null))) {
System.out.println(html);
html = br.readLine();
}
}
catch (NullPointerException e) {
return;
}
catch (Exception e) {
e.printStackTrace();
}
}
}
{
"args": {},
"headers": {
"Accept": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2",
"Host": "httpbin.org",
"User-Agent": "Java/16.0.1",
"X-Amzn-Trace-Id": "Root=1-60ebdd33-6afcea7b6527b0532e8eccc0"
},
"origin": "90.149.37.69",
"url": "http://httpbin.org/get"
}
Socketを用いたWebページの取得
IPアドレス(=ホスト名)
とポート番号
を指定してTCP/IP接続
を行う場合は、Socket
クラスを利用する。
import java.io.*;
import java.net.Socket;
class GetHTMLSocket {
public static void main(String[] args) {
try (
// 「ホスト名」「ポート番号」を指定してSocketオブジェクトを生成
Socket s = new Socket("httpbin.org", 80);
// Socketオブジェクト -> 入出力バイトストリームの生成
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
// バイトストリーム -> 文字ストリーム への変換を行うInputStreamReaderフィルタ、
// 文字ストリーム -> バイトストリーム への変換を行うOutputStreamWriterフィルタの生成
InputStreamReader ism = new InputStreamReader(is);
OutputStreamWriter osw = new OutputStreamWriter(os);
// バッファリングフィルタの生成
BufferedReader br = new BufferedReader(ism);
BufferedWriter bw = new BufferedWriter(osw);
) {
// GETリクエストの送信
bw.write("GET /get HTTP/1.1\n");
bw.write("Host: httpbin.org\n");
bw.write("\n");
// 強制書き込み
bw.flush();
// GETメソッドによる取得結果の表示
String str = "";
while (true) {
str = br.readLine();
if (str == null) {
break;
}
System.out.println(str);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
HTTP/1.1 200 OK
Date: Mon, 12 Jul 2021 06:12:27 GMT
Content-Type: application/json
Content-Length: 197
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
"args": {},
"headers": {
"Host": "httpbin.org",
"X-Amzn-Trace-Id": "Root=1-60ebdd4b-3a90ff7b7dfbebfc6dcd2d7c"
},
"origin": "90.149.37.69",
"url": "http://httpbin.org/get"
}
サーバーサイドプログラムの作成
参考: ソケット通信
指定したポート番号
で接続待機を行うサーバサイドプログラム
を実装する場合は、ServerSocket
クラスを利用する。
import java.io.*;
import java.net.*;
public class ServerSide {
public static void main(String[] args) {
try (
// 「待ち受けポート番号」の指定
ServerSocket svSocket = new ServerSocket(39648);
// クライアントサイドからの接続要求の待機
// -> 接続確立後は「クライアントIPアドレス」と「ポート番号」を保持するSocketオブジェクトが生成
Socket socket = svSocket.accept();
// サーバー -> クライアント への出力バイトストリームの生成
OutputStream os = socket.getOutputStream();
// 文字ストリーム -> バイトストリーム への変換を行うOutputStreamWriterフィルタの生成
OutputStreamWriter osw = new OutputStreamWriter(os);
// バッファリングフィルタの生成
BufferedWriter bw = new BufferedWriter(osw);
) {
// クライアントの情報の取得・出力
System.out.println("from: " + socket.getInetAddress());
// クライアントへの出力
bw.write("Hello!");
// 強制書き込み
bw.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
HTTPリクエスト/レスポンス
参考1: HTTPリクエスト/HTTPレスポンス
参考2: HTTPヘッダ
HTTPリクエスト
・HTTPレスポンス
の内部データ構造は、以下の通り。
// 1行目: リクエストライン
GET <リソースパス> HTTP/1.1
// 2行目-: リクエストヘッダ
Host: URLの先頭部分
Connection: トランザクション完了後の接続状態
Upgrade-Insequre-Requests: クライアントの設定情報
User-Agent: ブラウザのバージョン情報
Referer: 遷移元URL
Accept-Encoding: デコード可能なエンコーディング形式
Accept-Language: 利用可能言語
// 最終行: リクエストボディ
// -> サーバに追加・上書きするコンテンツ内容を記述(GET, DELETEの場合は空白行)
// 1行目: ステータスライン
HTTP/1.1 <ステータスコード>
// 2行目-(n-1)行目: レスポンスヘッダ
Date: 接続時刻
Server: Webサーバー名称・バージョン情報
Content-Length: リソースサイズ[Byte]
Keep-Alive: タイムアウトに関する設定情報
Connection: トランザクション完了後の接続状態
Content-Type: MIMEタイプ
// n行目: 区切り行(必ず空白行)
// n+1行目-: レスポンスボディ
<HTML情報>
ステータスコード
HTTPレスポンス
の実行結果を表すステータスコードは、以下の通り。
なお、100
番台は情報
、200
番台は正常
、300
番台はリダイレクト(転送)
、
400
番台はクライアント側エラー
、500番台
はサーバ側エラー
を表す。
分類 | コード | メッセージ | 内容 |
---|---|---|---|
成功 | 200 | OK | リクエストの成功 |
転送 | 301 | Moved Permanently | URLの恒久的な移動 |
302 | Moved Temporarily | URLの一時的な移動 | |
クライアント側エラー | 400 | Bad Request | 不正なリクエスト |
401 | Unauthorized | 認証の失敗 | |
403 | Forbidden | アクセス権なし | |
404 | Not Found | 存在しないURL | |
サーバ側エラー | 500 | Internal Server Error | 内部エラーの発生 |
502 | Bad Gateway | 無効のレスポンスが返却 | |
503 | Service Unavailable | サービス利用不可 |
HttpClient/HttpRequestを用いたデータの送信・追加
参考1: httpbinの紹介
参考2: httpbin
データ取得
以外のHTTPリクエスト
を送信する場合は、リクエスト内容
を保持するHttpRequest
クラスと
HTTPリクエスト
を送信するHttpClient
クラスを利用する。
import java.net.URI;
import java.net.http.*;
import java.net.http.HttpClient.Redirect;
import java.net.http.HttpClient.Version;
public class HTTPGetPost {
public static void main(String[] args) {
// HTTPリクエストを送信するHttpClientオブジェクトの生成
HttpClient client = HttpClient
// HttpClient.Builderオブジェクトの生成
.newBuilder()
// HTTPプロトコルのバージョン指定
.version(Version.HTTP_1_1)
// リダイレクトポリシーの指定
.followRedirects(Redirect.NORMAL)
// HttpClientオブジェクトの生成
.build();
// -- GETメソッド --
// HTTPリクエスト内容を保持するHttpRequestオブジェクトの生成
HttpRequest requestGet = HttpRequest
// HttpRequest.Builderオブジェクトの生成
.newBuilder()
// URLの指定
.uri(URI.create("http://httpbin.org/get"))
// HTTPリクエストメソッドの指定
.GET()
// HttpRequestオブジェクトの生成
.build();
// HTTPリクエストの送信
try {
HttpResponse<String> response = client.send(requestGet,
// レスポンスボディ(=HTML情報)を「文字列」として処理するHttpResponse.BodyHandlersクラスのメソッドを利用
HttpResponse.BodyHandlers.ofString()
);
// レスポンスボディの取得
String body = response.body();
// ステータスコードの取得
int status = response.statusCode();
// レスポンス内容の表示
System.out.println("status code: " + status);
System.out.println("-- response body(GET) --");
System.out.println(body);
}
catch (Exception e) {
e.printStackTrace();
}
// -- POSTメソッド --
// HTTPリクエスト内容を保持するHttpRequestオブジェクトの生成
HttpRequest requestPost = HttpRequest
// HttpRequest.Builderオブジェクトの生成
.newBuilder()
// URLの指定
.uri(URI.create("http://httpbin.org/post"))
// リクエストヘッダの追加
.header("Content-Type", "application/json")
// リクエストヘッダの追加
.header("Accept", "application/json")
// HTTPリクエストメソッドの指定
.POST(HttpRequest.BodyPublishers.ofString(
"Hello!"
))
// HttpRequestオブジェクトの生成
.build();
// HTTPリクエストの送信
try {
HttpResponse<String> response = client.send(requestPost,
// レスポンスボディ(=HTML情報)を「文字列」として処理するHttpResponse.BodyHandlersクラスのメソッドを利用
HttpResponse.BodyHandlers.ofString()
);
// レスポンスボディの取得
String body = response.body();
// ステータスコードの取得
int status = response.statusCode();
// レスポンス内容の表示
System.out.println("status code: " + status);
System.out.println("-- response body(POST) --");
System.out.println(body);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
status code: 200
-- response body(GET) --
{
"args": {},
"headers": {
"Content-Length": "0",
"Host": "httpbin.org",
"User-Agent": "Java-http-client/16.0.1",
"X-Amzn-Trace-Id": "Root=1-60ecd4a1-73b2e7923fe00bca0152d92f"
},
"origin": "90.149.37.69",
"url": "http://httpbin.org/get"
}
status code: 200
-- response body(POST) --
{
"args": {},
"data": "Hello!",
"files": {},
"form": {},
"headers": {
"Accept": "application/json",
"Content-Length": "6",
"Content-Type": "application/json",
"Host": "httpbin.org",
"User-Agent": "Java-http-client/16.0.1",
"X-Amzn-Trace-Id": "Root=1-60ecd4a1-46be2e1837f0f1e948219b43"
},
"json": null,
"origin": "90.149.37.69",
"url": "http://httpbin.org/post"
}
用語集
用語 | 内容 |
---|---|
ソケット(socket) |
IPアドレス とポート番号 の組み合わせ。 |
プロキシ(proxy) |
内部ネットワーク に接続されたホスト の代わりに外部ネットワーク にアクセスする機能。 |
Webアプリケーション(web application) |
HTTPリクエスト をトリガーとして、処理結果をHTML で返却するプログラム。 |
RFC(Request For Comment) |
IETF が定める標準化技術をまとめた文書。 |
ユーザエージェント(UA; user agent) |
クライアント 側で通信を行うソフトウェア。 |
冪等性(idempotent) | 同一リクエストを送信した場合でも副作用が生じない性質。 |
クエリパラメータ(query parameter) |
URL の末尾に? を付与し、キー と値 を指定することで表示結果を限定する補足情報。 |
REST(REpresentative State Transfer) | 一意なURL に対して、各リクエストメソッドを送信し、JSON/XML 形式でレスポンスを行うWeb API の設計哲学。 |