概要
Express 4 で、HTTPレスポンスヘッダーに "Content-Type" をマニュアルでセットする方法のハンズオン記録です
- "Content-Type" ヘッダをセットする書き方はよく見かけるアプローチだけでも
res.type, res.set, res.header, res.setHeader, res.writeHead がある - それぞれの書き方、結果について実際にやってみた
- 例として、HTTPレスポンス時 の HTTPヘッダー Content-Type が
Content-Type: text/plain; charset=utf-8
となるようにコードをかいてみる
先に、全体像 → Express で HTTPヘッダをセットする方法一覧
「"Hello" を "Content-Type: text/plain;" ヘッダつけてレスポンスする」いろんなやり方
メソッド | コード例 | 説明 |
res#type | res.type('text/plain'); res.send('Hello'); |
"content-type"ヘッダー設定専用メソッド |
res.type('.txt'); res.send(`Hello`); |
ファイル拡張子を指定すると適切なContent-Typeを設定してくれる | |
res#set | res.set('content-type', 'text/plain'); res.send('Hello'); |
ヘッダー名,値 で指定する |
res.set({'content-type': 'text/plain', 'x-original-header': 'original_value'}); res.send('Hello'); |
res#setで、ヘッダーを複数指定する書き方 | |
res#header | res.header('Content-Type', 'text/plain'); res.send('Hello'); |
res#set のエイリアス |
res.header({'content-type': 'text/plain', 'x-original-header': 'original_value'}); res.send('Hello'); |
ヘッダーを複数指定する書き方 | |
res#setHeader | res.setHeader('content-type', 'text/plain'); res.send(`Hello`); |
Node.js の 'http' モジュールに所属するメソッド |
res#writeHead | res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('Hello'); res.end();// 応答プロセスを終了する |
Node.js の 'http' モジュールに所属するメソッド res.sendとは併用できない |
本編
Expressで簡易サーバーを書く
実験用簡易サーバーを動作させて、HTTPヘッダーがどのように出力されるか curl で確認する
import express from 'express';
export default class HttpServer {
constructor() {
this.server = null;
}
async start(options = {}) {
const { port } = options;
const app = express();
app.get('test', (req, res) => {
// ここでいろいろ試す
res.set('content-type', 'text/plain');
res.send('Hello');
});
return new Promise((resolve) => {
this.server = app.listen(port, () => {
console.log(`Server started on port:${port}`);
resolve();
});
});
}
stop() {
this.server.close((() => {
console.log(`Server stopped`);
}));
}
}
(async () => {
const server = new HttpServer();
await server.start({ port: 8080 });
})()
ヘッダー確認用curl
curl --head http://localhost:8080/test
res.type
-
res#type をつかう。
-
res#type は "text/plain" のように"/"が含まれていたら、
Content-Type : text/plain
のように、そのまま反映するが、"/" 含まれていなければ、指定した文字列をファイル拡張子とみなして、MIMEタイプが検索され適切なContent-Type
が設定される。
コード
app.get('test', (req, res) => {
res.type('text/plain');
res.send('Hello');
});
結果
Content-Type: text/plain; charset=utf-8
- テキストファイルの拡張子を指定してみる
コード
app.get('/test', (req, res) => {
res.type('.txt');
res.send(`Hello`);
});
結果
ちゃんと "text/plain" になっている。
Content-Type: text/plain; charset=utf-8
こうしても結果は同じだった
app.get('/test', (req, res) => {
res.type('txt');
res.send(`Hello`);
});
res.set()
- res#set をつかう
コード
app.get('/test', (req, res) => {
res.set('content-type', 'text/plain');
res.send('Hello');
});
以下のように書くこともできる。こちらは、複数ヘッダをセットできる
app.get('/test', (req, res) => {
res.set({'content-type':'text/plain'});
res.send('Hello');
});
結果
HTTPヘッダーは以下のとおり。charset が自動付与されているが、Expressではデフォルトcharsetは"utf-8"となる。
Content-Type: text/plain; charset=utf-8
実際の応答はこんな感じ。ひとまず Content-Type に着目する。
curl --head http://localhost:8080/test
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/plain; charset=utf-8
Content-Length: 5
ETag: W/"5-9/+ei3uy4Jtwk1pdeF4MxdnQq/A"
Date: Thu, 24 Feb 2022 05:05:55 GMT
Connection: keep-alive
Keep-Alive: timeout=5
res#setでヘッダを複数指定してみる
app.get('/test', (req, res) => {
res.set(
{
'content-type': 'text/plain',
'x-original-header': 'original_value'
});
res.send('Hello');
});
結果
ちゃんと複数指定できていた。
Content-Type: text/plain; charset=utf-8
x-original-header: original_value
res.header
- res#header は res#set のエイリアス
なので、 res#set と等価(おんなじ)
コード
app.get('/test', (req, res) => {
res.header('Content-Type', 'text/plain');
res.send('Hello');
});
結果
Content-Type: text/plain; charset=utf-8
- setメソッドと同じく複数指定も可
app.get('/test', (req, res) => {
res.header(
{
'content-type': 'text/plain',
'x-original-header': 'original_value'
});
res.send('Hello');
});
res.setHeader
- res#setHeaderは Express ではなく Node.js のコアモジュールである 'http' モジュールがもつメソッド
コード
app.get('/test', (req, res) => {
res.setHeader('content-type', 'text/plain');
res.setHeader('x-original-header', 'original_value');
res.send(`Hello`);
});
結果
Content-Type: text/plain; charset=utf-8
x-original-header: original_value
res.writeHead
- res#writeHead は Express ではなく Node.js のコアモジュールである 'http' モジュールがもつメソッド
コード
- res.writeHead は res.send と併用できないので注意(理由は後述)
app.get('/test', (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('Hello');
res.end();// 応答プロセスを終了する
});
結果(ヘッダーぜんぶのせ)
curl --head http://localhost:8080/test
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/plain
Date: Thu, 24 Feb 2022 05:50:41 GMT
Connection: keep-alive
Keep-Alive: timeout=5
res.writeHeadとres.sendを併用できない理由
うっかり以下のようにしてしまうとエラーとなる
app.get('/test', (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.send(`hello`);
});
エラー
Cannot set headers after they are sent to the client
これは writeHead を実行すると、即座にレスポンスコードとヘッダ書き込みが起こるが、 res.send 内でも、再度 ヘッダ書き込みを行うため。
おまけ res.send 後に res.end は不要
app.get('/test', (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('Hello');
res.end();// 応答プロセスを終了する
});
この場合は res.endで応答のプロセスを終了しているが、 res.send の場合は res.send 内で res.end をしているので、 res.end は不要となる。
おまけ、その2: Content-Type ヘッダーを送出しない方法
- 以下のように、何も返さないで出力を終える ということもできる
この場合、 Content-type は付与されない
コード
app.get('/test', (req, res) => {
res.status(200).end();
});
結果(ヘッダーぜんぶのせ)
curl --head http://localhost:8080/test
HTTP/1.1 200 OK
X-Powered-By: Express
Date: Thu, 24 Feb 2022 05:59:52 GMT
Connection: keep-alive
Keep-Alive: timeout=5
- こうやっても同様に何も返さないで出力をおえる
コード
app.get('/test', (req, res) => {
res.status(200).send();
});
結果(ヘッダーぜんぶのせ)
curl --head http://localhost:8080/test
HTTP/1.1 200 OK
X-Powered-By: Express
Date: Thu, 24 Feb 2022 06:03:10 GMT
Connection: keep-alive
Keep-Alive: timeout=5
- res.send で空文字を返すと Content-Type は付与される
コード例
app.get('/test', (req, res) => {
res.status(200).send('');
});
結果(ヘッダーぜんぶのせ)
- Content-Length: 0 だが、Content-Type は text/html が付与される。
>curl --head http://localhost:8080/test
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 0
ETag: W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"
Date: Thu, 24 Feb 2022 06:03:34 GMT
Connection: keep-alive
Keep-Alive: timeout=5
関連