Express のレスポンス関連メソッド「res.end()」「res.send()」「res.json()」の違い

Express でレスポンスを返す時、res.end()res.send()res.json() などのメソッドを使用するが、それぞれの違いは何か、res.end() は必ず呼ばなければならないのか、あたりを調べた。

Express の API リファレンスを呼んでみる

まずは Express の API リファレンスを読んでみよう。

res.send()

The body parameter can be a Buffer object, a String, an object, or an Array.

When the parameter is an Array or Object, Express responds with the JSON representation:

色んなレスポンスが返せる汎用的なメソッド。引数に配列やオブジェクトを渡した場合は、Content-Typeapplication/json に設定して適切に処理してくれるようだ。

…じゃあ、res.json() との違いは?

res.json()

Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a JSON string using JSON.stringify().

引数のオブジェクトや配列などを JSON.stringify()string に直し、適切な Content-Type をセットしてレスポンスする。

…ふむ、ココまでは res.send() との違いを感じられない。

res.end()

Use to quickly end the response without any data. If you need to respond with data, instead use methods such as res.send() and res.json().

何のデータも返さない時に使う。データを返したい時は res.send()res.json() を使ってね、とのこと。

ということは、res.send('Hoge').end() とか res.json({ result: 'OK' }).end() みたいな呼び方はしなくて良い、ってことだな。疑問の一つは解決した。

res.send()res.json() の違いは?

res.send()res.json() と同じようなことができてるっぽいじゃん。何が違うの?ということで res.json() の実装を見てみよう。

コレを見ると、リクエストヘッダを設定し、JSON.stringify() したボディを res.send() に渡しているだけのようだ。

じゃあ res.send() の実装はというと。

res.send() の引数に Buffer でないオブジェクトが渡された場合は、res.json() を呼び出して JSON.stringify() をかけて再度 res.send() 自身を呼び出している。結局は、res.json()res.send() のエイリアス的な役割でしかなく、res.send() で JSON が送れるのも内部で res.json() を呼び出しているから、という関係のようだ。よく出来ている。

res.send() の引数 body が文字列になったら、ヘッダを調整して res.end() を呼んでレスポンスしている。この res.end()http.ServerResponse.prototype 由来のモノのようで、Express 側では特に何もしていないようだ。

res.end() が「何もデータを返さないレスポンス用のメソッド」なのではなく、Node.js の response.end() が求める引数を与えていないために空のレスポンスが返る、という仕組みのようだ。

結論

ということのようだ。