这是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
时,连接才会“完成”。
因此,如果仍有数据等待写入,并且接收客户端出于某种原因对接收此数据很狡猾,请求是否会结束?
我还看到了这样一个问题,即在尝试结束Flash上传程序发出的http请求时,结尾无效。我最终做了以下操作,这确实有所帮助:
res.end(failureJSON, 'utf8');
req.once('end', function _destroyConn() {
req.connection.destroy();
});
似乎非常hackish。无论如何,req.connection.destroy
需要保证与套接字断开连接的这种行为吗?
答案 0 :(得分:6)
不幸的是,res.end()
没有直接“保证断开套接字”,因为它需要考虑HTTP Keep-Alive。根据文档,end
告诉服务器已发送所有内容,并且响应已完成。无论是否立即断开连接,完全取决于服务器对象。
更具体地回答您的问题,重要的是响应需要发出finish
事件。如果你看一下_finish()
的实现,它几乎只是发出事件。
正如您所指出的那样,它并不总是直接调用_finish()
...但确实设置this.finished = true
。执行_flush()
时,会发送所有剩余数据,然后调用_finish()
。
这有点复杂,我不认为我可以在没有错误风险的情况下进一步细节。
就连接有时未关闭而言,您是否检查过是否正确配置了keep-alive
?如果HTTP连接默认设置为keep-alive
,则调用end
将不会关闭套接字。
如果您打印res.shouldKeepAlive
,它会告诉您服务器是否正在尝试使用keep-alive
。如果要阻止服务器执行此操作,请在请求处理程序的开头将其设置为false
。
答案 1 :(得分:0)
我不知道这是否对您有所帮助,因为我正在构建节点4.4+的框架,但我已确认您可以在响应中发送Connection: close
标头以获取节点以关闭连接。
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);
});
我不太确定这是否是您想要的关闭事件。我通常会尝试使用库并远离net
api,所以这只是猜测。