如何以编程方式停止 Node.js HTTP 服务器以便进程退出?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17958618/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 15:09:04  来源:igfitidea点击:

How do I stop a Node.js HTTP server programmatically such that the process exits?

node.js

提问by Dmitry Minkovsky

I'm writing some tests and would like to be able to start/stop my HTTP server programmatically. Once I stop the HTTP server, I would like the process that started it to exit.

我正在编写一些测试,并希望能够以编程方式启动/停止我的 HTTP 服务器。一旦我停止 HTTP 服务器,我希望启动它的进程退出。

My server is like:

我的服务器是这样的:

// file: `lib/my_server.js`

var LISTEN_PORT = 3000

function MyServer() {
  http.Server.call(this, this.handle) 
}

util.inherits(MyServer, http.Server)

MyServer.prototype.handle = function(req, res) { 
  // code 
}

MyServer.prototype.start = function() {
  this.listen(LISTEN_PORT, function() {
    console.log('Listening for HTTP requests on port %d.', LISTEN_PORT)
  })
}

MyServer.prototype.stop = function() {
  this.close(function() {
    console.log('Stopped listening.')
  })
}

The test code is like:

测试代码如下:

// file: `test.js`

var MyServer = require('./lib/my_server')
var my_server = new MyServer();

my_server.on('listening', function() {
  my_server.stop()
})

my_server.start()

Now, when I run node test.js, I get the stdoutoutput that I expect,

现在,当我运行时node test.js,我得到了stdout我期望的输出,

$ node test.js
Listening for HTTP requests on port 3000.
Stopped listening.

but I have no idea how to get the process spawned by node test.jsto exit and return back to the shell.

但我不知道如何让进程产生node test.js退出并返回到 shell。

Now, I understand (abstractly) that Node keeps running as long as there are bound event handlers for events that it's listening for. In order for node test.jsto exit to the shell upon my_server.stop(), do I need to unbind some event? If so, which event and from what object? I have tried modifying MyServer.prototype.stop()by removing all event listeners from it but have had no luck.

现在,我(抽象地)理解,只要 Node 正在侦听的事件有绑定的事件处理程序,它就会一直运行。为了node test.js退出到 shell on my_server.stop(),我是否需要解除绑定某些事件?如果是这样,哪个事件和来自哪个对象?我尝试MyServer.prototype.stop()通过从中删除所有事件侦听器来进行修改,但没有运气。

回答by user2041338

I've been looking for an answer to this question for months and I've never yet seen a good answer that doesn't use process.exit. It's quite strange to me that it is such a straightforward request but no one seems to have a good answer for it or seems to understand the use case for stopping a server without exiting the process.

几个月来我一直在寻找这个问题的答案,但我从未见过一个不使用process.exit. 我很奇怪这是一个如此简单的请求,但似乎没有人对此有好的答案,或者似乎理解停止服务器而不退出进程的用例。

I believe I might have stumbled across a solution. My disclaimer is that I discovered this by chance; it doesn't reflect a deep understanding of what's actually going on. So this solution may be incomplete or maybe not the only way of doing it, but at least it works reliably for me. In order to stop the server, you need to do two things:

我相信我可能偶然发现了一个解决方案。我的免责声明是我偶然发现了这一点;它并不反映对实际发生的事情的深刻理解。所以这个解决方案可能不完整,或者可能不是唯一的方法,但至少它对我来说是可靠的。为了停止服务器,您需要做两件事:

  1. Call .end()on the client side of every opened connection
  2. Call .close()on the server
  1. .end()在每个打开的连接的客户端上调用
  2. .close()在服务器上调用

Here's an example, as part of a "tape" test suite:

这是一个示例,作为“磁带”测试套件的一部分:

test('mytest', function (t) {
    t.plan(1);

    var server = net.createServer(function(c) {
        console.log("Got connection");
        // Do some server stuff
    }).listen(function() {
        // Once the server is listening, connect a client to it
        var port = server.address().port;
        var sock = net.connect(port);

        // Do some client stuff for a while, then finish the test

        setTimeout(function() {
            t.pass();
            sock.end();
            server.close();
        }, 2000);

    });

});

After the two seconds, the process will exit and the test will end successfully. I've also tested this with multiple client sockets open; as long as you end all client-side connections and then call .close()on the server, you are good.

两秒后,进程将退出,测试将成功结束。我还在打开多个客户端套接字的情况下对此进行了测试;只要你结束所有客户端连接,然后.close()在服务器上调用,你就很好。

回答by rocketspacer

http.Server#close

http.Server#close

https://nodejs.org/api/http.html#http_server_close_callback

https://nodejs.org/api/http.html#http_server_close_callback

module.exports = {

    server: http.createServer(app) // Express App maybe ?
                .on('error', (e) => {
                    console.log('Oops! Something happened', e));
                    this.stopServer(); // Optionally stop the server peacefully
                    process.exit(1); // Or violently
                 }),

    // Start the server
    startServer: function() {
        Configs.reload();
        this.server
            .listen(Configs.PORT)
            .once('listening', () => console.log('Server is listening on', Configs.PORT));
    },

    // Stop the server
    stopServer: function() {
        this.server
            .close() // Won't accept new connection
            .once('close', () => console.log('Server stopped'));
    }
}

Notes:

笔记:

  • "close"callback only triggers when all leftover connections have finished processing
  • Trigger process.exit in "close"callback if you want to stop the process too
  • “关闭”回调仅在所有剩余连接完成处理时触发
  • 如果您也想停止进程,请在“关闭”回调中触发 process.exit

回答by Rob Raisch

To cause the node.js process to exit, use process.exit(status)as described in http://nodejs.org/api/process.html#process_process_exit_code

要使 node.js 进程退出,请process.exit(status)按照http://nodejs.org/api/process.html#process_process_exit_code 中的说明使用

Update

更新

I must have misunderstood.

我一定是误会了。

You wrote: "...but I have no idea how to get the process spawned by node test.js to exit and return back to the shell."

你写道:“……但我不知道如何让节点 test.js 产生的进程退出并返回到 shell。”

process.exit() does this.

process.exit() 就是这样做的。

Unless you're using the child_processes module, node.js runs in a single process. It does not "spawn" any further processes.

除非您使用 child_processes 模块,否则 node.js 在单个进程中运行。它不会“产生”任何进一步的进程。

The fact that node.js continues to run even though there appears to be nothing for it to do is a feature of its "event loop" which continually loops, waiting for events to occur.

尽管 node.js 似乎无事可做,但它继续运行的事实是其“事件循环”的一个特性,它不断循环,等待事件发生。

To halt the event loop, use process.exit().

要停止事件循环,请使用 process.exit()。

UPDATE

更新

After a few small modifications, such as the proper use of module.exports, addition of semicolons, etc., running your example on a Linux server (Fedora 11 - Leonidas) runs as expected and dutifully returns to the command shell.

经过一些小的修改,例如正确使用 module.exports,添加分号等,在 Linux 服务器(Fedora 11 - Leonidas)上运行您的示例按预期运行并尽职尽责地返回到命令外壳。

lib/my_server.js

库/my_server.js

// file: `lib/my_server.js`

var util=require('util'),
    http=require('http');

var LISTEN_PORT=3000;

function MyServer(){
      http.Server.call(this, this.handle);
}
util.inherits(MyServer, http.Server);

MyServer.prototype.handle=function(req, res){
      // code
};

MyServer.prototype.start=function(){
    this.listen(LISTEN_PORT, function(){
            console.log('Listening for HTTP requests on port %d.', LISTEN_PORT)
    });
};

MyServer.prototype.stop=function(){
    this.close(function(){
        console.log('Stopped listening.');
    });
};

module.exports=MyServer;

test.js

测试.js

// file: `test.js`

var MyServer = require('./lib/my_server');

var my_server = new MyServer();

my_server.on('listening', function() {
    my_server.stop();
});

my_server.start();

Output

输出

> node test.js
Listening for HTTP requests on port 3000.
Stopped listening.
>

Final thoughts:

最后的想法:

I've found that the conscientious use of statement-ending semicolons has saved me from a wide variety of pernicious, difficult to locate bugs.

我发现认真使用语句结尾的分号使我免于各种有害的、难以定位的错误。

While most (if not all) JavaScript interpreters provide something called "automatic semicolon insertion" (or ASI) based upon a well-defined set of rules (See http://dailyjs.com/2012/04/19/semicolons/for an excellent description), there are several instances where this feature can inadvertently work against the intent of the programmer.

虽然大部分(如果不是全部)JavaScript解释器提供了“自动插入分号”(或ASI)基于一个定义良好的规则集叫做(见http://dailyjs.com/2012/04/19/semicolons/为优秀的描述),有几个实例可能会在不经意间违背程序员的意图。

Unless you are verywell versed in the minutia of JavaScript syntax, I would strongly recommend the use of explicit semicolons rather than relying upon ASI's implicit ones.

除非您非常精通 JavaScript 语法的细节,否则我强烈建议使用显式分号,而不是依赖 ASI 的隐式分号。