为什么我的快递路由器只在发送JSON时崩溃,而不是在发送文本时崩溃?

statusRouter.route('/') .all(function(req,res,next){ res.writeHead(200, {'Content-Type': 'application/json'}); next(); }) .get(function(req, res, next) { res.json({ name : "xyz" }); }); 

这崩溃了 – 标题不能被设置后,已被发送。
但是,这是可行的:

 statusRouter.route('/') .all(function(req,res,next){ res.writeHead(200, {'Content-Type': 'text/plain'}); next(); }) .get(function(req, res, next) { res.end("xyz"); }); 

注意:如果我在第一个发送JSON的情况下删除了writeHead函数,它也开始工作。 为什么当我做一个writeHead的时候它不工作? 这东西是让我疯狂的任何人都可以解释为什么发生这种情况
PS我正在与我自己的路由器快速生成的应用程序。

res.writeHead()res.end()都不是由Express实现的,而是由Node.js http模块实现的。

它的文档说明res.end()

如果指定了data ,则相当于调用response.write(data, encoding)接着是response.end(callback)

所以res.end("xyz")是简短的:

 res.write("xyz"); res.end(); 

对于res.write() ,文档指出:

如果调用此方法并且未调用response.writeHead() ,则将切换到隐式标题模式并清除隐式标题。

所以res.end("xyz") 实际上是简短的:

 if (! res.headersSent) { res.writeHead(...); } res.write("xyz"); res.end(); 

这意味着在使用res.end()之前,在您自己的代码中发出res.writeHead()是完全可以的。 在内部, http模块会知道你已经刷新了标题,所以它不会再做(因此防止你得到的错误)。 但是,一旦writeHead() ,就不能设置不同的标题或更改现有标题。

现在, res.json()是另外一个问题:这不是http模块的一部分,而是Express本身。 因为它被用来发送JSON响应,所以它将内容types头设置为application/json (所以你不必)。

但是这只有在头文件还没有被发送时才会起作用:当头文件已经被发送出去时,你不能设置头文件。 这就是为什么你得到错误。

如果您想在Express中设置特定的标题,请使用res.set()

Express按照它们添加的顺序评估其路由。 这意味着传递给.all()的路由处理程序将首先执行。 在这个处理程序中,写入了一个响应头,然后next()告诉Express继续迭代其路由列表以获得另一个可能的匹配路由。

然后匹配尝试发送JSON响应的.get()路由处理程序。 但是, .json() 隐式发送一个响应头 ,并将传递的值作为JSON写入响应并结束响应。 这就是为什么你看到一个关于writeHead()不止一次被调用的错误。