【问题标题】:close server from within router从路由器内部关闭服务器
【发布时间】:2021-02-27 13:39:40
【问题描述】:

我创建了一个这样的快递应用

const express = require('express')
const app = express();

app.use(express.static(path.join(__dirname, 'public')));

app.post('/close', async (_, res) => {
  res.status(200);
  res.end();
  app.close();
});

module.exports = app;

我在另一个模块中实例化它

const myApp = require('./app.js');
myApp.listen(port, () => {
  console.log(`Started server on ${port}`);
});

我希望服务器在收到对/close 的发布请求时自行关闭。目前,我只收到app.close is not a function 错误。

我知道我可以像这样在外部关闭服务器

const server = myApp.listen(port, () => {
  console.log(`Started server on ${port}`);
});
server.close();

但我想在对/close 的发布请求中关闭服务器,我该怎么做?

【问题讨论】:

  • 此处接受的答案可能会有所帮助。 stackoverflow.com/questions/14515954/…
  • @ozgur 它仍然使用我的应用无权访问的server 实例
  • 我现在明白了。可以使用事件来完成吗?
  • 你考虑过使用worker_threads吗?
  • @AdamAzad no...

标签: javascript node.js express nodejs-server


【解决方案1】:

要访问您的服务器对象,请尝试使用

req.connection.server

从您的路由处理程序中。

.close() makes the server stop listening 用于新连接。已经建立的连接不受影响。当所有打开的连接都断开时,服务器对象会发出 'close' 事件。

process.exit() 停止你的整个 nodejs 应用程序。

所以,这段代码可能会做你想做的事。

app.post('/close', (req, res, next) => {
  res.status(200)
  res.end()
  const server = req.connection.server
  if (server.listening) {
    server.addEventListener('close', ev => {
      console.log('server closed. See ya later alligator.')
      process.exit(0)
    })
    console.log('closing server')
    server.close()
  }
});

如果您需要从您的应用程序对象中获取服务器对象(如果从您的 req 对象中获取它还不够好),您可以放入一个像这样的小中间件函数。

app.use( function adornApp( req, res, next ) {
  req.app.locals.server = req.connection.server
  next()
} )

然后,一旦您的中间件被首次调用,您就可以从app.locals.server 获取您的服务器。

【讨论】:

  • 我对此进行了实验。实际终止服务器需要 2-3 次调用 close
  • 对。 .close() 使服务器停止监听。已经建立的连接不受影响。
【解决方案2】:

您可以使用http-terminator 包来关闭您的服务器。以下应该可以解决问题。我们之所以使用http-terminator,是因为如果通过路由访问,服务器不会关闭。

const { createHttpTerminator } = require("http-terminator");
const { initApp, app } = require("./app.js");

const PORT = 3000;

const server = app.listen(PORT, () => {
  console.log(`Started server on ${PORT}`);
});

const httpTerminator = createHttpTerminator({ server });

initApp(httpTerminator);

模块内部:

const express = require("express");
const app = express();

const initApp = (httpTerminator) => {
  app.get("/close", async (_, res) => {
    res.json({ message: "we closed" });
    await httpTerminator.terminate();
  });
};

module.exports = { initApp, app };

【讨论】:

  • 这仍然需要我的路由器无法访问的 httpServer 实例
  • @theonlygusti 您可以在模块中添加一个包装函数并将其导出。然后在函数内添加所有使用httpTerminator 实例的路由。见代码sn-p
  • @Reyno,很好的方法,但我认为 OP 想要关闭服务器而不必重构他的代码:访问服务器实例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-19
  • 1970-01-01
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多