使用node.js HTTP,res.end()如何保证套接字断开?

Tom*_*Tom 2 http httprequest node.js

这是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;
};
Run Code Online (Sandbox Code Playgroud)

资料来源: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();
    });
Run Code Online (Sandbox Code Playgroud)

似乎非常hackish.无论如何,是否req.connection.destroy需要保证与套接字断开连接?

log*_*yth 6

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

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

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

这有点复杂,我不认为我可以在没有错误风险的情况下进一步细节.

如果连接有时没有关闭,你检查一下你是否keep-alive配置正确吗?如果keep-alive默认设置HTTP连接,则调用end不会关闭套接字.

如果您打印出来res.shouldKeepAlive,它会告诉您服务器是否正在尝试使用keep-alive.false如果要阻止服务器执行此操作,请将其设置为请求处理程序的开头.