使用node.js HTTP,res.end()如何保证socket的连接?

这是node.js的end实现:

 OutgoingMessage.prototype.end = function(data, encoding) { if (this.finished) { return false; } if (!this._header) { this._implicitHeader(); } if (data && !this._hasBody) { console.error('This type of response MUST NOT have a body. ' + 'Ignoring data passed to end().'); data = false; } var ret; var hot = this._headerSent === false && typeof(data) === 'string' && data.length > 0 && this.output.length === 0 && this.connection && this.connection.writable && this.connection._httpMessage === this; if (hot) { // Hot path. They're doing // res.writeHead(); // res.end(blah); // HACKY. if (this.chunkedEncoding) { var l = Buffer.byteLength(data, encoding).toString(16); ret = this.connection.write(this._header + l + CRLF + data + '\r\n0\r\n' + this._trailer + '\r\n', encoding); } else { ret = this.connection.write(this._header + data, encoding); } this._headerSent = true; } else if (data) { // Normal body write. ret = this.write(data, encoding); } if (!hot) { if (this.chunkedEncoding) { ret = this._send('0\r\n' + this._trailer + '\r\n'); // Last chunk. } else { // Force a flush, HACK. ret = this._send(''); } } this.finished = true; // There is the first message on the outgoing queue, and we've sent // everything to the socket. if (this.output.length === 0 && this.connection._httpMessage === this) { debug('outgoing message end.'); this._finish(); } return ret; }; 

来源: https : //github.com/joyent/node/blob/master/lib/http.js#L645

显然,连接只是“完成” output.length === 0

那么,如果仍然有数据等待写入,并且由于某种原因,接收方客户端接收到这些数据是不合时宜的,请求是否会被终止?

我也看到了这样的问题,当试图结束由闪存上传器发出的http请求时,结束不起作用。 我结束了以下,这有助于:

  res.end(failureJSON, 'utf8'); req.once('end', function _destroyConn() { req.connection.destroy(); }); 

似乎非常hackish。 无论如何,这种行为与req.connection.destroy需要保证从sockets断开连接?

不幸的是, res.end()并不直接“保证套接字断开”,因为它需要考虑HTTP Keep-Alive。 根据文档, end告诉服务器,一切都已经发送,并且响应已经完成。 服务器对象完全取决于是否立即断开连接。

要更具体地回答您的问题,重要的是响应需要发出finish事件。 如果你看一下_finish()的实现,它几乎只是发出事件。

正如你所指出的,它并不总是直接调用_finish() ,但它确实设置了this.finished = true 。 当_flush()执行时,它发送任何剩余的数据,然后调用_finish()

这有点复杂,如果没有错误的风险,我不认为我可以做更多的细节。

至于连接有时不closures,你检查,如果你有keep-aliveconfiguration正确吗? 如果HTTP连接默认设置为keep-alive ,那么调用end将不会closures套接字。

如果你打印出res.shouldKeepAlive ,它会告诉你,如果你的服务器试图使用keep-alive 。 如果要停止服务器执行此操作,请在请求处理程序的开始处将其设置为false

我不知道这是否帮助你,因为我正在构build我的框架的节点4.4 +,但我已经确认,您可以发送Connection: close标头在您的响应让节点closures连接。

 let res = getResponseSomehow() res.statusCode = 408 res.setHeader("Connection", "close") res.end() 

另外你的销毁代码可以使用下面的调整:

 // First we give node the time to close the connection // We can give it 2 seconds let socket = getSocketSomehow(); let timer = setTimeout(function() { socket.destroy(); }, 2000); socket.on("close", function() { clearTimeout(timer); }); 

我不太确定这是否是你想要的closures事件。 我通常试图使用一个库,远离net API,所以这只是一个猜测。