今回遭遇したのは次のような問題
- Node.js側でPOST受信するPOST APIを定義
- クライアント側からそのAPIにPOST送信する
- その際FormDataによりデータを渡したい
- 上手くいかないので悩む…
POST送信する時にデータを渡すのですが、
それに multipart/form-data を使ってました。
ところがNode.js側でそれを受け取れてません。
その解決策が分かったのでメモしておきます。
このページの目次
クライアントからFormDataでPOST送信したが…
ちょうど次のような状況です。
▼ クライアント側 : POST送信コード例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/// 送信するFormData定義 const formData = new FormData(); formData('message', 'Hello'); /// Node.jsへとPOST送信 fetch('/api/hogehoge', { method: 'POST', headers: { 'Content-Type': "multipart/form-data" /// ^ Content-Type指定 }, body: formData /// ^ FormData添付 }.then(async (response)=>{ const result = await response.json(); console.log('result : ', result) }).catch((err)=>{ console.error(err); }); |
▼ Node.js側 : Post送信のRouter
1 2 3 4 5 6 7 8 9 10 11 |
const express = require("express"); const router = express.Router(); router.post('/api/hogehoge', async (req, res)=>{ /// FormDataを受け取れると思ったが… const message = req.body.message; /// 未定義となっている… console.log(message) /// => undefined }); |
このコードには2つほど間違いがありました。
そもそもNode.js / Express ではFormDataを標準的にサポートしていないようです。だからFormDataでPost送信しても req.body には未解析のデータが入っています。
それを解析できるモジュールが必要ということ
FormDataを扱えるNode.jsモジュールを探した
探してみると色々なモジュールがあります。
▼ FormData解析用のモジュール候補
- https://www.npmjs.com/package/express-form-data
- https://www.npmjs.com/package/multer
- https://www.npmjs.com/package/parse-multipart-data
- https://www.npmjs.com/package/formdata-parse
- https://www.npmjs.com/package/express-formidable
結論から言うと express-formidable を選びました、
どうしてかというと環境的な要因もあるのか、他4つは正常に機能しなかったからです。あと express-formidable は使い方もシンプルで分かりやすいから
npm経由でexpress-formidableをインストール
ということでnpmからインストールします。
▼ npmからexpress-formidableをインスト
1 |
$ npm install express-formidable |
ちなみにライセンスはMITで配布されてます。
受信したmultipart/form-dataを解析する
これでNode.js側でFormDataが解析できます。
具体的には次の2つが手に入ります。
- request.fields : 送信された非file以外のデータ
- request.files : 送信されたfilesのデータ
そして先ほどのRouterコードを改良しました。
▼ このようなコードに改良
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const express = require("express"); const router = express.Router(); const formidable = require('express-formidable'); router.use(formidable()); router.post('/api/hogehoge', async (req, res)=>{ /// 解析されたFormDataを取得 const message = req.fields.message; /// 今度はしっかり受け取れた console.log(message) /// => Hello }); |
POST送信されたFormDataを受け取りに成功!
全体ではなく個別Routerに適用できるのも便利です。
FormData送信時はContent-Type指定してはダメ
あとfetch送信時などに重要なことが1つ
それはContent-Typeを指定しないこと
だから以下のようなコードに修正しました。
▼ クライアント側 : fetchによるコードも改良
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/// 送信するFormData定義 const formData = new FormData(); formData('message', 'Hello'); /// Node.jsへとPOST送信 fetch('/api/hogehoge', { method: 'POST', headers: { /// 'Content-Type': "multipart/form-data" /// ^ 修正 : Content-Typeを未指定に }, body: formData /// ^ FormData添付 }.then(async (response)=>{ const result = await response.json(); console.log('result : ', result) }).catch((err)=>{ console.error(err); }); |
そうしないとexpress-formidableがエラーを吐きます。
なんでContent-Typeを指定してはいけないのか…
その理由はここに書くより次記事を見るのが早いです。
▼ FormDataをPOSTするときにContent-Typeを指定しない
多分Ajaxとか他APIでも同様かと思います。
この点にも注意が必要ですね。
Node.jsでFormData受信するポイントまとめ
ということで簡単にまとめます。
- Node自体はmultipart/form-dataに未対応
正確に書くならNode.js / Express ではFormDataにより送られた multipart/form-data のデータは解析できない。受信するには express-formidable のようなモジュール必要
- クライアント側でContent-Type指定は不要
それからクライアント側からFormDataを使ってNode側に送信する場合、Fetch API などでContent-Typeを指定してはいけない(Ajaxなど他APIでも同様)
この2点に注意しておけば大丈夫かと
以上、Node.jsで multipart/form-data を受信するでした。
もし間違ってる点などあれば教えてください。ではまた