http模塊中的writeHead


writeHead

response.writeHead(statusCode[, statusMessage][, headers])
statusMessage 好像沒什么用,一般用不到。
返回對 ServerResponse 的引用,以便可以鏈式調用。

const body = 'hello world';
response
  .writeHead(200, {
    'Content-Length': Buffer.byteLength(body),
    'Content-Type': 'text/plain'
  })
  .end(body);

如果在調用writeHead之前調用了 response.write() 或 response.end(),會報錯。

net::ERR_INVALID_CHUNKED_ENCODING

當使用 response.setHeader() 設置響應頭時,則與傳給 response.writeHead() 的任何響應頭合並,且 response.writeHead() 的優先。

res.setHeader('X-Foo', 'bar');
res.writeHead(200, { 'X-Foo': 'bar11' });
console.log(res.getHeader('Content-Type') ); // bar11

調用writeHead之后調用setHeader,報錯:

Cannot set headers after they are sent to the client
// 在源代碼中有如下的定義,這里是報錯的地方
OutgoingMessage.prototype.setHeader = function setHeader(name, value) {
  if (this._header) {
    throw new ERR_HTTP_HEADERS_SENT('set');
  }
}

如果調用此方法並且尚未調用 response.setHeader(),則直接將提供的響應頭值寫入網絡通道而不在內部進行緩存,響應頭上的 response.getHeader() 將不會產生預期的結果。

response.writeHead(200, { 'Content-Type': 'text/plain' });
console.log(response.getHeader('Content-Type') ); // undefined
// 沒有內部緩存導致獲取不到剛剛設置的'content-type'

對比先調用response.setHeader,再調用writeHead:

res.setHeader('X-Foo', 'bar');
res.writeHead(200, { 'Content-Type': 'text/plain' });
console.log(res.getHeader('Content-Type') ); // 'text/plain'
// 可以獲取到剛剛設置的content-type

如果需要漸進的響應頭填充以及將來可能的檢索和修改,則改用 response.setHeader()。

// 返回 content-type = text/plain
const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/html');
  res.setHeader('X-Foo', 'bar');
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('ok');
});

之前在遇到一個問題:

代碼中只是重新定義了res.writeHead,在向客戶端返回數據的時候會自動調用res.writeHead,問題在於代碼中並沒有調用writeHead ?

var http = require('http')
var server  = http.createServer(function (req,res) {
    var _ = res.writeHead
    res.writeHead = function(...arg){
        console.log(arg);
        _.call(this,arg)
    }
    res.write('adfasdfsf') // 調用write會觸發writeHead
    res.end()
})
server.listen(10899,function () {
    console.log(121212);
})

通過斷點跟蹤發現有如下的邏輯鏈條:

ObjectSetPrototypeOf(ServerResponse.prototype, OutgoingMessage.prototype);// 原型繼承,response上面的部分方法繼承自OutgoingMessage

// write方法,當調用response.write的時候就是調用的這里
OutgoingMessage.prototype.write = function write(chunk, encoding, callback) {
  const ret = write_(this, chunk, encoding, callback, false);
  if (!ret)
    this[kNeedDrain] = true;
  return ret;
};

function write_(msg, chunk, encoding, callback, fromEnd) {
  if (!msg._header) {
    msg._implicitHeader();
  }
}

// 調用writeHead,所以只要執行write方法就會調用writeHead方法	
ServerResponse.prototype._implicitHeader = function _implicitHeader() {
  this.writeHead(this.statusCode);
};

ServerResponse.prototype.writeHead = writeHead;
function writeHead(statusCode, reason, obj) {}

同樣在在調用response.end的時候也有類似的處理:

ServerResponse.prototype.end繼承自OutgoingMessage.prototype.end

OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
 ......
  if (chunk) {
 		.........
    write_(this, chunk, encoding, null, true);
  } else if (this.finished) {
    ......
  } else if (!this._header) {
    this._contentLength = 0;
    this._implicitHeader();
  }
}
// 如果傳入了第一個參數,調用write_,接下來就是上面的步驟
// 如果沒有傳入參數,並且沒有header,直接調用了_implicitHeader,其實就是this.writeHead(this.statusCode);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM