Java 18 Simple Web Server (jwebserver) Tutorial

Introduction Sometimes you just need to serve some files over HTTP - to look at a static website you are building, to try out a page that will not work from file://, to share files on a local network, or to give a test a URL to fetch. Python developers have long done this with python -m http.server. Java 18Click to read tutorial: Overview of New Features in Java 18 (JEP 408) added the equivalent to the JDK: the Simple Web Server, started with the jwebserver command, plus an API to start it from Java code. This tutorial explains jwebserver with examples: running it from the command line and its options, what it can and cannot do, and using the SimpleFileServer API in a program or a test. Running jwebserver Running jwebserver in a directory serves that directory, by default on port 8000 of the loopback address -
cd my-site
jwebserver
Opening http://127.0.0.1:8000/ in a browser then shows index.html if there is one, or a listing of the directory, and every request is logged in the terminal. Its options are -  OUTPUT of jwebserver --help
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 - the port, for example jwebserver -p 9000.
  • -b - the address to bind to. The default is the loopback address, so only your own machine can connect; -b 0.0.0.0 makes the server reachable from other machines on the network.
  • -d - the directory to serve, instead of the current directory.
  • -o - how much to log: none, info (the default) or verbose, which also logs request and response headers.
The same server can also be started with java -m jdk.httpserver, which accepts the same options.
What it can and cannot do The Simple Web Server is deliberately minimal. It is meant for prototyping, testing, education and ad-hoc file sharing - not for production -
  • It serves static files only, and only answers GET and HEAD requests; other methods get a 405 Method Not Allowed or 501 Not Implemented.
  • It sets the Content-Type from the file extension, and generates directory listings.
  • It speaks HTTP/1.1 only, with no HTTPS, no authentication, no caching headers and no compression.
  • It does not follow symbolic links and does not serve hidden files, as a basic safety measure.
Starting a file server from Java code The server is built on the com.sun.net.httpserver package of the jdk.httpserver module, which has existed since Java 6. Java 18 added the class SimpleFileServer to it, which creates a ready-made file server in one line. That is handy in tests which need a real URL. The example below serves a temporary directory on a free port, fetches files from it with the Java 11 HTTP ClientClick to read: Java 11 HTTP Client, and stops it -
Serving a directory with SimpleFileServer
//FileServerDemo.java
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.SimpleFileServer;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;

public class FileServerDemo {
  public static void main(String[] args) throws Exception {
    Path root = Files.createTempDirectory("site");
    Files.writeString(root.resolve("index.html"), "<h1>Hello from jwebserver</h1>");
    Files.writeString(root.resolve("data.json"), "{\"release\": 18}");

    HttpServer server = SimpleFileServer.createFileServer(
        new InetSocketAddress(InetAddress.getLoopbackAddress(), 0),     // port 0: pick a free port
        root, SimpleFileServer.OutputLevel.NONE);
    server.start();
    String base = "http://localhost:" + server.getAddress().getPort();

    HttpClient client = HttpClient.newHttpClient();
    for (String path : new String[] {"/", "/data.json", "/missing.txt"}) {
      HttpResponse<String> r = client.send(HttpRequest.newBuilder(URI.create(base + path)).build(),
          HttpResponse.BodyHandlers.ofString());
      System.out.printf("GET %-12s -> %d %-25s %s%n", path, r.statusCode(),
          r.headers().firstValue("Content-Type").orElse("-"), r.statusCode() == 200 ? r.body() : "");
    }
    server.stop(0);
  }
}
 OUTPUT of the above code
GET /            -> 200 text/html                 <h1>Hello from jwebserver</h1>
GET /data.json   -> 200 application/json          {"release": 18}
GET /missing.txt -> 404 text/html; charset=UTF-8
Explanation of the code
  • SimpleFileServer.createFileServer(address, root, outputLevel) returns an ordinary HttpServer, configured to serve files from root, which must be an absolute path. Binding to port 0 lets the operating system choose a free port, which avoids clashes when tests run in parallel.
  • A request for / returns index.html; the content types text/html and application/json come from the file extensions; a missing file gives a 404.
  • SimpleFileServer also has createFileHandler(), which returns just the handler so that it can be added to your own server next to other contexts, and createOutputFilter() for request logging.
Beyond static files Java 18 also added HttpHandlers, with ready-made handlers such as HttpHandlers.of(statusCode, headers, body) for a fixed response, and Request-based filters - enough to stub a simple API in a test without a framework. For anything more, such as a real web application, use a proper server or framework. Summary In this tutorial we saw how Java 18's Simple Web Server serves static files from a directory with the single command jwebserver, went through its options for the port, bind address, directory and logging, and saw its deliberate limits - static files, GET and HEAD only, no HTTPS, not for production. We then started a file server from Java code with SimpleFileServer, fetched files from it, and saw the other helpers added for tests. Next, read about code snippets in JavadocClick to read tutorial: Java 18 Code Snippets in Javadoc with @snippet.