java

最小構成の Java API を作りながら HttpServer の内部を理解する

Tomcat や Jetty といったサーブレットコンテナは、Servlet API(HttpServlet / doGet / doPost)を使って HTTP リクエストを処理します。しかし今回は、Servlet API を使わず、
JDK に付属する軽量 HTTP サーバ(HttpServer)を直接起動してHTTP リクエストを処理する方法を試してみます。

com.sun.net.httpserver.HttpServer とは

JDK に標準で付属している、最小限の機能だけを持つ HTTP サーバです。TomcatやJettyのようなフル機能サーバ(Servletコンテナを持つ)ではありませんが単純な接続確認などには 依存ゼロで動くし十分使えます。

最小構成 API のコード
import com.sun.net.httpserver.HttpServer;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.time.LocalDateTime;

public class SampleApi {
    private static final int PORT = 8080;
    public static void main(String[] args) throws Exception {
        
        // サーバインスタンス生成(まだスレッドは起動しない)
        HttpServer server = HttpServer.create(new InetSocketAddress(PORT), 0);
        
        // ハンドラ登録
        server.createContext("/sample-api3", exchange -> {
            String clientIp = exchange.getRemoteAddress().getAddress().getHostAddress();
            
            // アクセスログ(IPアドレス・メソッド・パス)
            System.out.printf(
                "[%s] %s %s from %s%n",
                LocalDateTime.now(),
                exchange.getRequestMethod(),
                exchange.getRequestURI(),
                clientIp
            );
            
            String json = String.format(
               "{\"status\":\"SUCCESS\",\"time\":\"%s\",\"clientIp\":\"%s\"}",
                LocalDateTime.now(),
                clientIp
            );
            
            byte[] bytes = json.getBytes();
            exchange.getResponseHeaders().set("Content-Type", "application/json; charset=UTF-8");
            exchange.sendResponseHeaders(200, bytes.length);
            
            try (OutputStream os = exchange.getResponseBody()) {
                //レスポンスボティをバイト列でソケットに書き込む
                os.write(bytes);
            }
        });
        
        // シャットダウンフックでCtrl+cをキャッチし終了
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("Stopping server...");
            server.stop(0); // 0 = 即時停止(graceful ではない)
            System.out.println("Server stopped.");
        }));

        // 受付スレッド起動(内部でServerSocket.accept()が呼ばれ待機状態(I/O待ち)となる)
        server.start();
        System.out.println("Connectivity Test Server started on port " + PORT);
    }
}
実際に動作を確認する

今回の検証環境はJava21で実施しています。そのためソースプログラムをそのまま実行し検証することができています。

# こんなに簡単にHttpサーバを立てる事できます
#
test >> java -version
openjdk version "21" 2023-09-19
OpenJDK Runtime Environment (build 21+35-2513)
OpenJDK 64-Bit Server VM (build 21+35-2513, mixed mode, sharing)
test >> java .\sampleapi3.java
Connectivity Test Server started on port 8080
[2026-06-14T16:59:47.473168300] GET /sample-api3/ from 0:0:0:0:0:0:0:1
# 別ターミナルからcurlで確認
#
test >> curl localhost:8080/sample-api3/ | ConvertFrom-Json | ConvertTo-Json
  % Total    % Received % Xferd  Average Speed  Time    Time    Time   Current
                                 Dload  Upload  Total   Spent   Left   Speed
100     85 100     85   0      0   1322      0                              0
{
  "status": "SUCCESS",
  "time": "2026-06-14T16:59:47.474169",
  "clientIp": "0:0:0:0:0:0:0:1"
}
test >>
# サーバを終了するにはCtrl+c
#
test >> java .\sampleapi3.java
Connectivity Test Server started on port 8080
[2026-06-14T16:56:02.493516600] GET /sample-api3 from 0:0:0:0:0:0:0:1
[2026-06-14T16:59:24.650131800] GET /sample-api3/ from 0:0:0:0:0:0:0:1
[2026-06-14T16:59:47.473168300] GET /sample-api3/ from 0:0:0:0:0:0:0:1
Stopping server...
Server stopped.
test >>

スポンサーリンク
タイトルとURLをコピーしました