Simple Web Server in Java 18 – Java 中的简单网络服务器 18

最后修改: 2024年 2月 25日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Starting in Java 18 we’ve access to the Simple Web Server, which was introduced in JEP 408.  We can access its functionality through a command line tool and an API.

从 Java 18 开始,我们可以访问 JEP 408 中引入的简单 Web 服务器。 我们可以通过命令行工具和 API 访问其功能。

The Simple Web Server offers a bare-bones web server that serves static files. It’s described as being useful for testing, prototyping, and education. The server is intentionally very simple to set up and run and doesn’t aim to compete with or replace more fully functional options such as Apache Tomcat or Jetty.

简单网络服务器提供了一个可提供静态文件的简易网络服务器。据介绍,它适用于测试、原型设计和教育。该服务器的设置和运行非常简单,并不打算与功能更全面的选项(如 Apache TomcatJetty )竞争或取代它们。

One of the goals of introducing the tool is to get developers up and running with web development with the fewest possible barriers.

推出该工具的目的之一是让开发人员以尽可能少的障碍启动和运行网络开发。

In this tutorial, we’ll learn about Simple Web Server and how it works.

在本教程中,我们将了解简单网络服务器及其工作原理。

2. jwebserver Command-Line Tool

2. jwebserver 命令行工具

The first and easiest way to start up a server is to use the provided command-line tool.

启动服务器的第一种也是最简单的方法是使用提供的命令行工具。

2.1. Startup

2.1 启动

The command we need here is jwebserver. Using the command jwebserver by itself is enough to start the server up.

使用jwebserver命令本身就足以启动服务器。

We see this response if everything is working:

如果一切正常,我们就会看到这个响应:

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

By default, the directory we’re in when we run the command is the one served, so /usr, in the example above. However, we can change the directory with the -d flag:

默认情况下,我们运行命令时所处的目录就是服务的目录,如上例中的 /usr。不过,我们可以使用 -d 标志更改目录:

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

Notably, we have to provide an absolute path here.

值得注意的是,我们必须在此处提供绝对路径。

We can also change the port and address with the -p and -b flags:

我们还可以使用-p-b标志更改端口和地址:</em

$ jwebserver -b 0.0.0.0 -p 3003    
Serving / and subdirectories on 0.0.0.0 (all interfaces) port 3003
URL http://192.168.1.1:3003/

Running the above configuration exposes our current directory to anyone on our network at the IP address given in the output. While this may be useful if we’re trying to transfer files we should be sure we’re happy to share them first.

运行上述配置后,我们的当前目录就会暴露给输出中给出 IP 地址的网络上的任何人。如果我们要传输文件,这可能会很有用,但我们应该先确定自己是否愿意共享这些文件。

2.2. GET Requests

2.2 GET 请求

We can access the web server using a browser to navigate to the correct address and port. Once we’re there we’ll see a list of files and subdirectories from within the directory from where we started the server:

我们可以使用浏览器访问网络服务器,导航到正确的地址和端口。一旦我们到达那里,就会看到我们启动服务器的目录中的文件和子目录列表:

If we then access any of these files we’ll see them in our browser and also a new line in our terminal:

如果我们访问这些文件中的任何一个,我们就会在浏览器中看到它们,同时也会在终端中看到一行新的内容:

127.0.0.1 - - [09/Feb/2024:12:06:26 +0000] "GET /file.txt HTTP/1.1" 200 -

Similarly, when entering a new subdirectory we’ll see the GET request logged with the directory we’re accessing:

同样,在进入一个新的子目录时,我们会看到 GET 请求记录了我们正在访问的目录:

127.0.0.1 - - [09/Feb/2024:12:06:52 +0000] "GET /subdirectory/ HTTP/1.1" 200 -

3. API

3.应用程序接口

The second option for working with the Simple Web Server is the API. By using it, we can gain a lot more control and customize how requests are handled.

使用简单网络服务器的第二个选择是 API。通过使用它,我们可以获得更多控制权,并自定义处理请求的方式。

3.1. Defining a Server

3.1.定义服务器

To start let’s recreate our command-line web server using the API.

首先,让我们使用 API 重新创建命令行网络服务器。

To do this we’ll use the class SimpleFileServer. We can use this class for three things – creating a HttpServer, creating a HttpHandler, and creating a HttpFilter.

为此,我们将使用类SimpleFileServer.我们可以使用该类做三件事:创建 HttpServer、创建 HttpHandler 和创建 HttpFilter

First, we’ll just create and start a server using createFileServer():

首先,我们将使用 createFileServer() 创建并启动一个服务器:

public static void main(String[] args) {
    InetSocketAddress address = new InetSocketAddress(8080);
    Path path = Path.of("/");
    HttpServer server = SimpleFileServer.createFileServer(address, path, SimpleFileServer.OutputLevel.VERBOSE);
    server.start();
}

Here we’ve specified an address, using the InetSocketAddress class. We also could have changed the rest of the address here and not just the port.

在这里,我们使用 InetSocketAddress 类指定了一个地址。我们还可以更改地址的其他部分,而不仅仅是端口。

We’ve then set up a Path object leading to the directory we want to serve.

然后,我们设置了一个 Path 对象,该对象通向我们要提供服务的目录。

Next, we’ve passed these in as arguments, along with the logging level, to createFileServer(). As before, we can configure any of these to meet our needs. The resulting web server is identical to the one created using the command line tool and can be accessed via our browser at 127.0.0.1:8080.

接下来,我们将这些参数与日志级别一起传递给 createFileServer() 。与之前一样,我们可以对其中任何一个参数进行配置,以满足我们的需要。生成的网络服务器与使用命令行工具创建的服务器完全相同,可以通过浏览器127.0.0.1:8080进行访问。

3.2. Handlers

3.2 处理程序

Clearly, creating the server above didn’t offer any benefits over the command line tool. To start gaining some control, we’ll need to introduce a HttpHandler.

显然,与命令行工具相比,创建上述服务器并没有带来任何好处。要开始获得一些控制权,我们需要引入一个 HttpHandler.

Let’s look at adding a custom one to our server. We can create a handler using another method from SimpleFileServercreateFileHandler(). Assuming we then already have a server like the one created earlier, we can attach our new handler to it:

让我们看看如何在服务器中添加一个自定义处理程序。我们可以使用 SimpleFileServer 中的另一个方法 createFileHandler() 来创建一个处理程序。假设我们已经有了一个像先前创建的那样的服务器,我们就可以将新的处理程序附加到它上面:

HttpHandler handler = SimpleFileServer.createFileHandler(Path.of("/Users"));
server.createContext("/test", handler);

This results in all traffic to 127.0.0.1:8080/test going through our new handler.

这将导致 127.0.0.1:8080/test 的所有流量通过我们的新处理程序。

We can use handlers to do much more than this. For example, let’s set up a server that simulates being allowed and denied access on different endpoints. We can use the method HttpHandlers.of() to create responses for both allowing and denying access:

我们可以使用处理程序做更多的事情。例如,让我们建立一个服务器,模拟允许和拒绝不同端点的访问。我们可以使用方法 HttpHandlers.of() 来创建允许访问和拒绝访问的响应:

HttpHandler allowedResponse = HttpHandlers.of(200, Headers.of("Allow", "GET"), "Welcome");
HttpHandler deniedResponse = HttpHandlers.of(401, Headers.of("Deny", "GET"), "Denied");

Next, we need a Predicate defined to decide when to return each response:

接下来,我们需要定义一个 Predicate 来决定何时返回每个响应:

Predicate<Request> findAllowedPath = r -> r.getRequestURI()
  .getPath().equals("/test/allowed");

This returns true only when we try and access the URL /test/allowed. All other endpoints fail.

只有当我们尝试访问 URL /test/allowed 时,才会返回 true。所有其他端点都会失败。

We can now use HttpHandlers.handleOrElse(), which takes our Predicate and both options. It performs the first if the Predicate passes, otherwise the second:

现在我们可以使用 HttpHandlers.handleOrElse(),它接受我们的 Predicate 和两个选项。如果 Predicate 通过,则执行第一个选项,否则执行第二个选项:

HttpHandler handler = HttpHandlers.handleOrElse(findAllowedPath, allowedResponse, deniedResponse);

Finally, we can set up our HttpServer as before using the new HttpHandler:

最后,我们可以使用新的 HttpHandler 像以前一样设置 HttpServer

HttpServer server = SimpleFileServer.createFileServer(address, path, SimpleFileServer.OutputLevel.VERBOSE);
server.createContext("/test", handler);

The result is that navigating to http://127.0.0.1:8080/test/allowed shows the text ‘Welcome‘ with a 200 response. Navigating to any other path displays ‘Denied‘ with a 401 response. We can use this as needed to set up test environments. The potential complexity is quite low, however.

结果是,导航到 http://127.0.0.1:8080/test/allowed 会显示文本”欢迎“和 200 响应。导航到任何其他路径都会显示’拒绝‘,并得到 401 响应。我们可以根据需要使用它来建立测试环境。不过,潜在的复杂性很低。

3.3. Filters

3.3 过滤器

The final aspect of the SimpleFileServer class is the ability to create a Filter. The role of this Filter will be to handle log messages. By defining our own we can redirect our messages to an OutputStream of our choosing.

SimpleFileServer 类的最后一个方面是创建 Filter 的能力。该 Filter 的作用是处理日志信息。通过定义我们自己的过滤器,我们可以将消息重定向到我们选择的 OutputStream 中。

The creation of the server is different when applying a Filter. First, let’s create the Filter using createOutputFilter():

在应用 Filter 时,服务器的创建有所不同。首先,让我们使用 createOutputFilter() 创建 Filter

Filter filter = SimpleFileServer.createOutputFilter(System.out, SimpleFileServer.OutputLevel.INFO);

We’ve used System.out as a simple example of an OutputStream here, but we could have used a logger or anything else we wanted.

我们在这里使用 System.out 作为 OutputStream 的一个简单示例,但我们也可以使用日志记录器或其他任何我们想要的东西。

Next, we’ll use the create() method from the HttpServer class with the filter we just made:

接下来,我们将使用 HttpServer 类中的 create() 方法和刚才制作的过滤器:

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

There are a few arguments there, so let’s go through them. First, the address is in the form of an InetSocketAddress as before. Second, an integer specifies the socket backlog. This is the maximum number of TCP connections allowed to queue at once. Third, we have the context. Here we’ve specified we want to deal with traffic hitting 127.0.0.1:8080/test. The fourth argument is a HttpHandler, similar to the one we created earlier. Finally comes our Filter as the fifth argument.

这里有几个参数,让我们一起来看看。首先,地址和以前一样是 InetSocketAddress 的形式。其次,一个整数指定了套接字积压。这是允许同时排队的 TCP 连接的最大数量。第三,是上下文。在这里,我们指定要处理访问 127.0.0.1:8080/test 的流量。第四个参数是 HttpHandler,类似于我们之前创建的那个。最后是我们的 Filter 作为第五个参数。

This provides the same functionality as when we used a handler before. However, we now have complete control over the log output.

这提供的功能与我们之前使用处理程序时的功能相同。不过,我们现在可以完全控制日志输出。

4. Conclusion

4.结论

In this article, we’ve seen that we can quickly spin up Java 18’s Simple Web Server and that it provides a small amount of helpful functionality.

在本文中,我们已经看到可以快速启动 Java 18 的简单 Web 服务器,而且它还提供了少量有用的功能。

First, we saw that by using the command-line tool jwebserver we can have a server up and running in moments. This server provides read access to the files and subdirectories in the location we run it.

首先,我们看到通过使用命令行工具 jwebserver 我们可以在瞬间启动并运行一个服务器。该服务器提供对运行位置的文件和子目录的读取访问。

Following that, we looked at the API and the new classes available such as SimpleFileServer. Using this API we could achieve the same results as the command-line tool, but programmatically. We could also extend our control using HttpHandler and Filter.

随后,我们查看了 API 和可用的新类,例如 SimpleFileServer 。使用该 API,我们可以实现与命令行工具相同的结果,但却是通过编程实现的。我们还可以使用 HttpHandlerFilter 扩展我们的控件。

As always, the full code for the examples is available over on GitHub.

与往常一样,这些示例的完整代码可在 GitHub 上获取。