如何以编程方式关闭ExpressJS实例进行测试?


106

我试图弄清楚如何关闭Express实例。基本上,我想跟.listen(port)电话相反-如何让Express服务器停止监听,释放端口并干净地关机?

我知道这似乎是一个奇怪的查询,所以这里是上下文;也许还有另一种方法可以解决这个问题,而我正在考虑错误的方法。我正在尝试为我的socket.io/nodejs应用设置测试框架。这是一个单页应用程序,因此在我的测试脚本中(我正在使用Mocha,但这并不重要)我希望能够启动服务器,针对它运行测试,然后关闭服务器。我可以通过假设在测试开始之前打开服务器电源,或者通过其中一个测试启动服务器,然后让每个后续测试都假设它已启动来解决此问题,但这确实很麻烦。我更希望每个测试文件使用适当的设置启动服务器实例,然后在测试结束后关闭该实例。这意味着运行测试没有任何怪异的依赖关系,并且一切都很干净。这也意味着我可以进行启动/关闭测试。

那么,有关如何执行此操作的任何建议?我曾考虑过手动触发异常以降低异常,但这似乎很混乱。我已经研究过Express文档和源代码,但似乎找不到任何可以关闭服务器的方法。为此,socket.io中可能还包含一些内容,但是由于套接字服务器只是连接到Express服务器,因此我认为这需要在Express层进行。

Answers:


156

事情发生了变化,因为快递服务器不再从节点http服务器继承。幸运的是,app.listen返回了服务器实例。

var server = app.listen(3000);

// listen for an event
var handler = function() {
  server.close();
};

23
对于Mocha测试,在您需要的地方('app'),我扩展到了app对象:app.server = app.listen(3000); 所以以后我可以说:var app = require('./ app'); app.server.close();
Jack Chi

2
在测试服务器时,请访问github.com/visionmedia/supertest,它将使您无需启动实际的服务器即可进行测试
Lukas Liesis '16

我也建议您将完成的回调传递给server.close()从挂钩中调用的回调。
Ullauri

注意:Express应用程序实例“ app”与返回值“ app.listen”之间存在很大差异,app.listen是具有“ close”方法的基础本机HTTP Server实例。@JackChi在上面暗示了这一点。
ajxs

这不会导致打开的开放客户端套接字出现问题吗?
卡梅隆·塔克林德

18

使用app.close()。完整示例:

var app = require('express').createServer();
app.get('/', function(req, res){
  res.send('hello world');
});
app.get('/quit', function(req,res) {
  res.send('closing..');
  app.close();
});
app.listen(3000);

调用app.close()回调函数内部时,测试已经结束。但是请记住,该进程仍在运行(尽管不再监听)。

如果在此之后,您需要结束该过程,请致电process.exit(0)

链接:

app.close:http ://nodejs.org/docs/latest/api/http.html#server.close (相同)

process.exit:http : //nodejs.org/docs/latest/api/process.html#process.exit


1
完美,正是我想要的。我想我在Express中找不到它,因为他们正在扩展核心节点http服务器,而我对此并不完全了解。谢谢!
drewww

感谢Srijan,这对我也有帮助-Adam
Hopkinson

这仍然是真的吗?express.createServer被标记为已弃用,并给出错误消息,指出应用程序不再从http.js的服务器继承
Frank Schwieterman

4
这不是有效的,因为快递3
gprasant

4
公开这样关闭服务器的URL并不是恕我直言。
shime

2

我已经多次回答了“如何终止HTTP服务器”的变体 支持渠道。不幸的是,我不能推荐任何现有的库,因为它们缺少一种或另一种方式。从那以后,我整理了一个软件包(我相信)可以处理所有正常HTTP服务器终止的情况。

https://github.com/gajus/http-terminator

http-terminator的主要好处是:

  • 它没有猴子补丁Node.js API
  • 它会立即破坏所有套接字,而不会附加HTTP请求
  • 它允许持续进行HTTP请求的套接字正常超时
  • 它可以正确处理HTTPS连接
  • 它通过设置连接来使用keep-alive通知连接服务器正在关闭:close标头
  • 它不会终止Node.js进程

Express.js的用法:

import express from 'express';
import {
  createHttpTerminator,
} from 'http-terminator';

const app = express();

const server = app.listen();

const httpTerminator = createHttpTerminator({
  server,
});

await httpTerminator.terminate();

0
//... some stuff 

var server = app.listen(3000);
server.close();

-1

通过编写bash脚本来启动服务器,运行测试并停止服务器,您可以轻松地做到这一点。这样做的好处是,您可以为该脚本添加别名,以快速,轻松地运行所有测试。

我在整个连续部署过程中都使用了此类脚本。您应该查看Jon Rohan的《 Dead Simple Git工作流程》,以获取有关此方面的一些见解。


2
这会起作用,但是如果可能的话,我更喜欢无bash的解决方案。也许这是一个愚蠢的偏好,但我想从测试环境中启动/停止服务器,因为它使编写特定于服务器配置的测试+启动/关闭测试更加容易。另外,它没有引入必须通过单独的脚本运行与服务器相关的测试的间接含义。
drewww

为什么要编写特定于环境的测试?也许我错了,但这使我感到不道德。我会尽量使您的测试与环境无关,因为无论您的开发环境如何,您都希望您的测试在整个团队中都能正常工作。
乔什·史密斯

我认为我在这里不执行任何特定于环境的操作。服务器将有几种不同的启动选项(例如,从文件中读取配置选项,从数据存储中加载状态等),最好在与我测试其他所有内容的相同框架中进行测试。我还想进行一些测试,例如,关闭服务器,再次将其重新备份,并确保它在此过程中不会丢失状态。如果我可以从节点以编程方式进行操作,那也比在bash中测试代码要容易得多。
drewww

您不会将测试代码放在bash本身中。您只需启动服务器并从脚本运行测试,就像在命令行上自己做一样。那里没有真正的特殊魔术。
乔什·史密斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.