为什么我的快递路由器只在发送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()
不止一次被调用的错误。