服务请求后停止 HttpServer

Stop HttpServer after request are served

我正在使用来自 com.sun.net.httpserver 的简单 Http 服务器,如 中所述。

一切正常,但我不确定一旦我不再需要它时如何彻底关闭服务器。我不想在服务器仍在为某些请求发送数据时停止服务器,只有在它空闲时才停止。

我的特定场景是执行 OAuth 舞蹈的桌面应用程序。我使用应用程序中嵌入的本地 Web 服务器提供回调响应,应用程序启动桌面浏览器以使用 java.awt.Desktop.browse API 显示服务器响应。

在将响应页面写入 HttpExchange 响应输出流后,我尝试直接从我的 HttpHandler.handle 函数调用 HttpServer.stop(0),但这为时过早,浏览器显示 ERR_EMPTY_RESPONSE.

当我的主应用程序完成其工作后我停止服务器时也会发生同样的情况 - 这通常为时过早,HttpServer 在那一刻尚未完成发送数据。

我可以提供几秒的延迟值来停止,但我想实现正确且干净的同步。

什么是正确的解决方案?

我可以提供一个基于 CountDownLatch + 自定义 ExecutorService 的解决方案,它被设置为 HttpServer 的执行者:

public void runServer() throws Exception {
    final ExecutorService ex = Executors.newSingleThreadExecutor();
    final CountDownLatch c = new CountDownLatch(1);

    HttpServer server = HttpServer.create(new InetSocketAddress(8888), 0);

    server.createContext("/test", (HttpExchange h) -> {
        StringBuilder resp = new StringBuilder();
        for (int i = 0; i < 1_000_000; i++)
            resp.append(i).append(", ");
        String response = resp.toString();
        h.sendResponseHeaders(200, response.length());
        OutputStream os = h.getResponseBody();
        os.write(response.getBytes());
        os.close();
        c.countDown();           // count down, letting `c.await()` to return
    });

    server.setExecutor(ex);      // set up a custom executor for the server
    server.start();              // start the server
    System.out.println("HTTP server started");
    c.await();                   // wait until `c.countDown()` is invoked
    ex.shutdown();               // send shutdown command to executor
    // wait until all tasks complete (i. e. all responses are sent)
    ex.awaitTermination(1, TimeUnit.HOURS); 
    server.stop(0);
    System.out.println("HTTP server stopped");
}

我确实在我们的工作网络环境中对此进行了测试,它似乎可以正常工作。 HttpServer 在响应完全发送之前停止,所以我认为这正是您所需要的。

另一种方法可能不是关闭执行器 ex,而是在将响应写入流后向那里发送一个包含 server.stop() 的新任务。由于 ex 是单线程构造的,因此此类任务的执行时间不会早于前一个任务完成,即。 e.回复已发送完毕:

public void run() throws Exception {
    final ExecutorService ex = Executors.newSingleThreadExecutor();
    final HttpServer server = HttpServer.create(new InetSocketAddress(8888), 0);

    server.createContext("/test", (HttpExchange h) -> {
        // ... generate and write a response
        ex.submit(() -> { 
            server.stop(0); 
            System.out.println("HTTP server stopped"); 
        });
    });
    server.setExecutor(ex); 
    server.start();
    System.out.println("HTTP server started");
}

有关详细信息,请参阅 ExecutorService

旧 post,但我想为其他感兴趣的人推荐一个替代方案。我知道您想关闭服务器,但您真的需要吗?不接受请求还不够吗?

我正在处理服务器作为另一个 java 应用程序的一部分启动的情况。在处理程序中有一个标志,并在满足所需条件后更新它,然后停止接受请求。这样,如果您希望在更新标志后接收请求,您还可以向客户端发送一些有用的信息。