0
0

More than 3 years have passed since last update.

【Java発展学習9日目】Java標準ライブラリを用いたネットワークアクセス

Last updated at Posted at 2021-07-12

ネットワーク通信における低水準(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

低水準APIOSI参照モデル物理層〜トランスポート層を担っており、
高水準APIセッション層〜アプリケーション層を担う。


URLを用いたHTML情報の取得

参考: jsoup(外部ライブラリ)
Java標準ライブラリを用いてHTML情報を取得する場合、URLクラスのopenStream()メソッドを用いることで、
バイトストリームを経由してデータを取得(=GET)することができる。

GetHTML.java
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クラスを利用する。

GetHTMLSocket.java
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クラスを利用する。

ServerSide.java
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レスポンスの内部データ構造は、以下の通り。

HTTPリクエスト
// 1行目: リクエストライン
GET <リソースパス> HTTP/1.1

// 2行目-: リクエストヘッダ
Host: URLの先頭部分
Connection: トランザクション完了後の接続状態
Upgrade-Insequre-Requests: クライアントの設定情報
User-Agent: ブラウザのバージョン情報
Referer: 遷移元URL
Accept-Encoding: デコード可能なエンコーディング形式
Accept-Language: 利用可能言語

// 最終行: リクエストボディ
// -> サーバに追加・上書きするコンテンツ内容を記述(GET, DELETEの場合は空白行)

HTTPレスポンス
// 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クラスを利用する。

HTTPGetPost.java
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の設計哲学。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0