【Modern Java】Java18で追加された Simple Web Server (JEP 408)

f:id:Naotsugu:20200724174249p:plain

blog1.mammb.com


JEP 408:Simple Web Server

すぐに使用できる静的ファイルのみを提供する最小限のWebサーバーが追加されました。

Webサーバーは、コマンドラインツールから起動できる他、コードからAPIを介して利用することができます。

このツールは、主に教育のコンテキストやプロトタイピング、テストなどにおいて、簡素なWebサーバーが必要な場合に役立ちます。


jwebserver

jwebserver というコマンドラインツールが追加されました。 このツールによりSimple Web サーバーを簡単に起動できます。

パスを通しておけば、

export PATH=$JAVA_HOME/bin:$PATH

以下のように起動できます。

$ jwebserver

Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::".
Serving .... and subdirectories on 127.0.0.1 port 8000
URL http://127.0.0.1:8000/

f:id:Naotsugu:20220324220622p:plain

デフォルトでは起動ディレクトリがルートとなり、8000 ポートでリスンされます。

ポートとルートディレクトリを指定するには以下のようにオプション指定します。

$ jwebserver -p 9000 -d /path/to/root

ヘルプは以下で確認できます。

$ jwebserver -h
Usage: jwebserver [-b bind address] [-p port] [-d directory]
                  [-o none|info|verbose] [-h to show options]
                  [-version to show version information]
Options:
-b, --bind-address    - Address to bind to. Default: 127.0.0.1 (loopback).
                        For all interfaces use "-b 0.0.0.0" or "-b ::".
-d, --directory       - Directory to serve. Default: current directory.
-o, --output          - Output format. none|info|verbose. Default: info.
-p, --port            - Port to listen on. Default: 8000.
-h, -?, --help        - Prints this help message and exits.
-version, --version   - Prints version information and exits.
To stop the server, press Ctrl + C.

主に使うのは、-p でポートを指定するのと、-d でディレクトリを指定するぐらいでしょう。

HTTPリクエストは、HTTP/1.1のみがサポートされ、HEADおよびGET要求のみで他のリクエストは、501 または 405 レスポンスとなります。

  • GET要求されたリソースがファイルの場合、そのコンテンツが提供される
  • GET要求されたリソースが index.html ファイルを含むディレクトリの場合 index.html が提供される
  • それ以外の場合は、ディレクトリ名が一覧される


API からのサーバ起動

jwebserver ではなく、コードからサーバを起動する場合は以下のようになります。

var server = SimpleFileServer.createFileServer(
        new InetSocketAddress(8000),
        Path.of("/some/path"),
        SimpleFileServer.OutputLevel.INFO);
server.start();


より細かいカスタマイズは、HttpServer.create() を使うことで可能です。

以下のような API となっています。

public static HttpServer create(InetSocketAddress addr,
                                int backlog,
                                String path,
                                HttpHandler handler,
                                Filter... filters) throws IOException {
    Objects.requireNonNull(path);
    Objects.requireNonNull(handler);
    Objects.requireNonNull(filters);
    Arrays.stream(filters).forEach(Objects::requireNonNull);

    HttpServer server = HttpServer.create(addr, backlog);
    HttpContext context = server.createContext(path);
    context.setHandler(handler);
    Arrays.stream(filters).forEach(f -> context.getFilters().add(f));
    return server;
}

例えば以下のように実装することでカスタマイズが可能です。

var handler = HttpHandlers.handleOrElse(
        (Request r) -> r.getRequestMethod().equals("PUT"),
        new PutHttpHandler(),
        new FallbackHandler());

var filter = Filter.adaptRequest(
        "Add Foo header",
        (Request r) -> r.with("Foo", List.of("Bar")));

var server = HttpServer.create(
        new InetSocketAddress(8000),
        10,
        "/",
        handler,
        filter);

server.start();

HttpHandler は1.6時代からのハンドラを実装したものを使います。

static class PutHttpHandler implements HttpHandler {
    @Override
    public void handle(HttpExchange exchange) throws IOException {
        ...
    }
}

static class FallbackHandler implements HttpHandler {
    @Override
    public void handle(HttpExchange exchange) throws IOException {
        ...
    }
}


まとめ

JDK18 で追加された Simple Web Server について紹介しました。

node や Nginx を使わず、ちょっと試したいといった場合に便利です。