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