提供请求后停止HttpServer

时间:2016-03-21 10:02:04

标签: java http httpserver

我正在使用com.sun.net.httpserver中的简单Http服务器,如simple HTTP server in Java using only Java SE API中所述。

一切正常,但我不确定如果我不再需要它,我怎么能干净地关闭服务器。我不想在服务器仍在为某些请求发送数据时停止服务器,只有在它处于空闲状态时才会停止。

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

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

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

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

对此有什么合适的解决方案?

2 个答案:

答案 0 :(得分:2)

我可以根据一个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是单线程构造的,因此这个任务将在不早于先前任务完成的情况下执行,即。即响应已完全发送:

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

答案 1 :(得分:0)

旧帖子,但我想为其他感兴趣的人推荐一个替代方法。我了解您要关闭服务器,但是您确实需要关闭服务器吗?仅仅不接受请求就足够了吗?

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