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
Opening
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 -
OUTPUT of the above code
Explanation of the code
Beyond static files
Java 18 also added
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
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 --helpUsage: 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 examplejwebserver -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.0makes 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) orverbose, which also logs request and response headers.
java -m jdk.httpserver, which accepts the same options.
- It serves static files only, and only answers
GETandHEADrequests; other methods get a405 Method Not Allowedor501 Not Implemented. - It sets the
Content-Typefrom 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.
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);
}
}
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
SimpleFileServer.createFileServer(address, root, outputLevel)returns an ordinaryHttpServer, configured to serve files fromroot, 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
/returnsindex.html; the content typestext/htmlandapplication/jsoncome from the file extensions; a missing file gives a 404. SimpleFileServeralso hascreateFileHandler(), which returns just the handler so that it can be added to your own server next to other contexts, andcreateOutputFilter()for request logging.
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.Continue Reading Java 18 to 21 Tutorials
Overview of New Features in Java 18Click to read tutorial: Overview of New Features in Java 18 Java 18 UTF-8 by Default: What Changes and WhyClick to read tutorial: Java 18 UTF-8 by Default: What Changes and Why Java 18 Code Snippets in Javadoc with @snippetClick to read tutorial: Java 18 Code Snippets in Javadoc with @snippet Java 18 Deprecates Finalization: Use Cleaner InsteadClick to read tutorial: Java 18 Deprecates Finalization: Use Cleaner Instead Overview of New Features in Java 19Click to read tutorial: Overview of New Features in Java 19 Overview of New Features in Java 20Click to read tutorial: Overview of New Features in Java 20 Overview of New Features in Java 21Click to read tutorial: Overview of New Features in Java 21 Java 21 Virtual Threads Tutorial with ExamplesClick to read tutorial: Java 21 Virtual Threads Tutorial with Examples Java 21 Record Patterns with ExamplesClick to read tutorial: Java 21 Record Patterns with Examples
Overview of New Features in Java 18Click to read tutorial: Overview of New Features in Java 18 Java 18 UTF-8 by Default: What Changes and WhyClick to read tutorial: Java 18 UTF-8 by Default: What Changes and Why Java 18 Code Snippets in Javadoc with @snippetClick to read tutorial: Java 18 Code Snippets in Javadoc with @snippet Java 18 Deprecates Finalization: Use Cleaner InsteadClick to read tutorial: Java 18 Deprecates Finalization: Use Cleaner Instead Overview of New Features in Java 19Click to read tutorial: Overview of New Features in Java 19 Overview of New Features in Java 20Click to read tutorial: Overview of New Features in Java 20 Overview of New Features in Java 21Click to read tutorial: Overview of New Features in Java 21 Java 21 Virtual Threads Tutorial with ExamplesClick to read tutorial: Java 21 Virtual Threads Tutorial with Examples Java 21 Record Patterns with ExamplesClick to read tutorial: Java 21 Record Patterns with Examples