はじめに
Node.jsを勉強していて、setHeaderとwriteHeadって何が違うの...?となったのでソースコードなどから調べてみました。
setHeaderのソースコードを見てみる
setHeaderの実装部分を示します。setHeaderはheadersに名前と値を格納しているだけということがわかります。
headersに値を格納しているので、例えばgetHeader(name)によって値を取得することができます。
OutgoingMessage.prototype.setHeader = function setHeader(name, value) {
if (this._header) {
throw new ERR_HTTP_HEADERS_SENT('set');
}
validateHeaderName(name);
validateHeaderValue(name, value);
let headers = this[kOutHeaders];
if (headers === null)
this[kOutHeaders] = headers = ObjectCreate(null);
headers[name.toLowerCase()] = [name, value];
};
(https://github.com/nodejs/node/blob/master/lib/_http_outgoing.js)
writeHeadのソースコードを見てみる
writeHeadの一部を抜き出したものを示します。
this[kOutHeaders]がtruthyな値かどうかで場合分けがされています。this[kOutHeaders]はヘッダーの名前と値をキャッシュしているデータになるので、setHeader()などでキャッシュされているかどうかで分かれることになります。
setHeader()が呼び出されていた場合、writeHeadの内部でもsetHeader()が実行され、writeHeadの引数で指定した名前と値もキャッシュされます。
一方、setHeader()が呼び出されていない場合、引数で指定した名前と値をheadersに格納するだけとなります。
let headers;
if (this[kOutHeaders]) {
// Slow-case: when progressive API and header fields are passed.
let k;
if (ArrayIsArray(obj)) {
if (obj.length % 2 !== 0) {
throw new ERR_INVALID_ARG_VALUE('headers', obj);
}
for (let n = 0; n < obj.length; n += 2) {
k = obj[n + 0];
if (k) this.setHeader(k, obj[n + 1]);
}
} else if (obj) {
const keys = ObjectKeys(obj);
for (let i = 0; i < keys.length; i++) {
k = keys[i];
if (k) this.setHeader(k, obj[k]);
}
}
if (k === undefined && this._header) {
throw new ERR_HTTP_HEADERS_SENT('render');
}
// Only progressive api is used
headers = this[kOutHeaders];
} else {
// Only writeHead() called
headers = obj;
}
(https://github.com/nodejs/node/blob/299984561eff45bddc5bb802e5b22d47277e5ca5/lib/_http_server.js)
具体例
setHeaderを使っている場合は、console.log(res.getHeader("content-Type"));が実行されると
content-Type':'text/html; charset=UTF-8と表示されます。
"use strict"
const http = require("http");
const server = http.createServer((req, res) => {
res.setHeader('Set-Cookie', "accessed_date=" + Date.now() + ";");
res.writeHead(200, {
'content-Type':'text/html; charset=UTF-8'
});
res.end();
console.log(res.getHeader("content-Type")); // => 'content-Type':'text/html; charset=UTF-8'
});
const port = 8000;
server.listen(port, () => {
console.info("listening on" + port);
})
setHeaderを使っていない場合undefinedと表示されます。
"use strict"
const http = require("http");
const server = http.createServer((req, res) => {
res.writeHead(200, {
'content-Type':'text/html; charset=UTF-8'
});
res.end();
console.log(res.getHeader("content-Type")); // => undefined
});
const port = 8000;
server.listen(port, () => {
console.info("listening on" + port);
})
まとめ
- setHeaderを使うと値をキャッシュすることができる
- 例えばgetHeaderなどで値を取り出すことができる
- setHeaderの実行後はwriteHeadでも値のキャッシュが行われるようになる
- writeHeadだけを使うと値のキャッシュなどが行われない
- その分、処理は早くなる