簡體   English   中英

如何以編程方式停止 Node.js HTTP 服務器以便進程退出?

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

我正在編寫一些測試,並希望能夠以編程方式啟動/停止我的 HTTP 服務器。 一旦我停止 HTTP 服務器,我希望啟動它的進程退出。

我的服務器是這樣的:

// 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.')
  })
}

測試代碼如下:

// 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()

現在,當我運行node test.js ,我得到了我期望的stdout輸出,

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

但我不知道如何讓node test.js產生的進程退出並返回到 shell。

現在,我(抽象地)理解,只要 Node 正在偵聽的事件有綁定的事件處理程序,它就會一直運行。 為了讓node test.jsmy_server.stop()上退出到 shell,我是否需要解除某些事件的綁定? 如果是這樣,哪個事件和來自哪個對象? 我嘗試通過從中刪除所有事件偵聽器來修改MyServer.prototype.stop()但沒有運氣。

幾個月來我一直在尋找這個問題的答案,但我從未見過不使用process.exit的好答案。 我很奇怪這是一個如此簡單的請求,但似乎沒有人對此有好的答案,或者似乎理解停止服務器而不退出進程的用例。

我相信我可能偶然發現了一個解決方案。 我的免責聲明是我偶然發現了這一點; 它並不反映對實際發生的事情的深刻理解。 所以這個解決方案可能不完整,或者可能不是唯一的方法,但至少它對我來說是可靠的。 為了停止服務器,您需要做兩件事:

  1. 在每個打開的連接的客戶端調用.end()
  2. 在服務器上調用.close()

這是一個示例,作為“磁帶”測試套件的一部分:

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);

    });

});

兩秒后,進程將退出,測試將成功結束。 我還在打開多個客戶端套接字的情況下對此進行了測試; 只要你結束所有客戶端連接,然后在服務器上調用.close() ,你就很好。

http.Server#close

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 gracefully
                    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'));
    }
}

筆記:

  • “關閉”回調僅在所有剩余連接完成處理時觸發
  • 如果您也想停止進程,請在“關閉”回調中觸發 process.exit

要使 node.js 進程退出,請使用http://nodejs.org/api/process.html#process_process_exit_code 中所述的process.exit(status)

更新

我一定是誤會了。

你寫道:“……但我不知道如何讓節點 test.js 產生的進程退出並返回到 shell。”

process.exit() 就是這樣做的。

除非您使用 child_processes 模塊,否則 node.js 在單個進程中運行。 它不會“產生”任何進一步的進程。

盡管 node.js 似乎無事可做,但它繼續運行的事實是其“事件循環”的一個特性,它不斷循環,等待事件發生。

要停止事件循環,請使用 process.exit()。

更新

經過一些小的修改,例如正確使用 module.exports,添加分號等,在 Linux 服務器(Fedora 11 - Leonidas)上運行您的示例按預期運行並盡職盡責地返回到命令外殼。

庫/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;

測試.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();

輸出

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

最后的想法:

我發現認真使用語句結尾的分號使我免於各種有害的、難以定位的錯誤。

雖然大多數(如果不是全部)JavaScript 解釋器基於一組明確定義的規則提供稱為“自動分號插入”(或 ASI)的東西(參見http://dailyjs.com/2012/04/19/semicolons/優秀的描述),有幾個實例可能會在不經意間違背程序員的意圖。

除非您非常精通 JavaScript 語法的細節,否則我強烈建議使用顯式分號,而不是依賴 ASI 的隱式分號。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM