Express.js はデフォルトの charset として UTF-8 が設定されます。
ほとんどのケースではこの振る舞いで問題はないのですが、クライアント側が UTF-8 を認識/取り扱いできないようなケース(IoT クライアントなど)で問題が発生します。
Express.js でレスポンスを返す場合、以下のようにすると思います。
router.get('/foo/var/baz', (req, res) => {
res.status(200)
res.set('Content-Type: text/csv; charset=us-ascii')
res.send('key,value\r\nhoge,fuga\r\npiyo,puyo')
})
このサーバに対して curl でリクエストを送ると、以下のようになります。
$ curl -i localhost:3000/foo/bar/baz
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/csv; charset=utf-8
Content-Length: 31
ETag: W/"1f-l8FL4++qBiqYIj/prv0x2jtd7e8"
Date: Fri, 09 Aug 2019 03:05:26 GMT
Connection: keep-alive
key,value
hoge,fuga
piyo,puyo
Content-Type が勝手に UTF-8 に書き換わっています。
これは Charset UTF-8 appended to Content-Type when using res.json · Issue #2921 · expressjs/express によるとどうやら仕様のようで、要約すると:
If you leave it up to us to choose UTF-8, we're going to modify your Content-Type header, that's just how it is.
UTF-8 を選択するのであれば、私達の方でで Content-Type ヘッダを変更するのでお任せください。
ということです。
任意の charset を指定したい場合は、以下のように行います。
### Buffer を使用する
```js
router.get('/foo/var/baz', (req, res) => {
res.status(200)
res.set('Content-Type: text/csv; charset=us-ascii')
res.set('Content-Type', 'text/csv; charset=us-ascii')
res.send(Buffer.from('key,value\r\nhoge,fuga\r\npiyo,puyo'))
})
$ curl -i localhost:3000/foo/bar/baz
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/csv; charset=us-ascii
Content-Length: 31
ETag: W/"1f-l8FL4++qBiqYIj/prv0x2jtd7e8"
Date: Fri, 09 Aug 2019 03:09:53 GMT
Connection: keep-alive
key,value
hoge,fuga
piyo,puyo
これが最も簡単な対応方法だと思います。
write/end を使用する
router.get('/foo/var/baz', (req, res) => {
res.status(200)
res.set('Content-Type: text/csv; charset=us-ascii')
res.write('key,value\r\nhoge,fuga\r\npiyo,puyo')
res.end()
})
$ curl -i localhost:3000/foo/bar/baz
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/csv; charset=us-ascii
Date: Fri, 09 Aug 2019 03:06:47 GMT
Connection: keep-alive
Transfer-Encoding: chunked
key,value
hoge,fuga
piyo,puyo
この方法は Buffer を使用する方法と異なり新たにオブジェクトを生成しないのですが、Transfer-Encoding が chunked になり、Content-Length ヘッダがなくなってしまいます。