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);