フォームからアップロードされたファイルを Express で 受取る方法
マルチパート形式の POST データ
HTML の form タグの enctype 属性に multipart/form-data を指定すると、 フォームをサブミットした時のデータ形式がいわゆる「マルチパート」という形式になります。
具体的に言うと、次ようなフォームがあるとします。
<form method="POST" enctype="multipart/form-data">
<input name="country">
<input name="city">
</form>
このとき、country、city にそれぞれ Japan、Tokyo という値を入力してサブミットすると、次のようなデータが POST されます (HTTP のヘッダー部分は大部分省略してあります)。
POST /foo HTTP/1.1 Accept: */* Cache-Control: no-cache Host: localhost:3000 Content-Type: multipart/form-data; boundary=MYBOUNDRY Content-Length: xxx --MYBOUNDRY Content-Disposition: form-data; name="country" Japan --MYBOUNDRY Content-Disposition: form-data; name="city" Tokyo --MYBOUNDRY--
ポイントは Content-Type が multipart/form-data となり、 HTTP のボディー部がバウンダリー (境界線) で複数の部分に分割されているところです。
そして、分割されたそれぞれの部分の中にさらに、ヘッダー部とボディ部があり、それぞれの部分の内容が記述できるようになっています。
フォームからファイルのアップロードを行う場合には、マルチパート形式を用います。
効率の良し悪しを抜きにすれば、上の例のように単なる文字列データをポストするのに使っても構いませんが、通常、単純な文字列データの場合は、form タグのデフォルトエンコーディングタイプである application/x-www-form-urlencoded を使います。 「POST されたフォームデータを Express で 受け取る方法」も参考にしてください。
multer を利用してマルチパート形式のポストデータを読み込む
Express でマルチパート形式の POST データを読み込むには、 multer というライブラリを利用すると便利です。
multer は次のコマンドでインストールできます。
npm install multer
multer ミドルウェアを Express に設定すれば、 Content-Type が multipart/form-data であるときにボディ部を解析し、 リクエストオブジェクトの body プロパティや files プロパティにその内容がセットされます。
フォームからアップロードしたファイルを読み込む例
ファイルをアップロードするコードを書いて動作を確認してみましょう。
まず Node のプロジェクトを作成して、 express と multer をインストールします。
mkdir test
cd test
npm init -y
npm install express multer
HTML ファイルを保存するためのフォルダを public という名前で作成します。
mkdir public
public フォルダ内に test.html という名前で次のファイルを作成します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Param 1</title>
<style>
body {
font-family: Arial, Helvetica, sans-serif;
}
form {
display: flex;
flex-direction: column;
max-width: 300px;
}
</style>
</head>
<body>
<form method="POST" action="/foo" enctype="multipart/form-data">
<input type="text" name="country" placeholder="country" />
<input type="text" name="city" placeholder="city" />
<input type="file" name="files" />
<input type="file" name="files" />
<input type="file" name="files" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
アップロードしたファイルを (一時) 保存するフォルダを、 uploads という名前で作成します。
mkdir uploads
次の内容を test.js として作成します。
const express = require('express')
const multer = require('multer')
const app = express()
// static built-in middleware
app.use(express.static('public'))
// multer middleware
const upload = multer({ dest: 'uploads/' })
app.post('/foo', upload.array('files', 3), (req, res) => {
console.log('--- post() /foo called ---')
console.log('--- req.body --')
console.log(req.body)
console.log('--- req.files ---')
console.log(req.files)
res.send('Done')
})
// Start Listenings
app.listen(3000, () => console.log('Listening on http://localhost:3000/...'))
multer のミドルウエアを作成しているのは 7-8行目です。
7行目でアップロードされたファイルを保存するディレクトリを指定しています。
8行目の upload.array('files', 3) でアップロードされるファイルの HTML の input 要素の name と、 ファイルの最大個数を指定しています。
以上で準備ができました。
このスクリプトを実行しましょう。
node test.js
Listening on http://localhost:3000/...
ブラウザから http://localhost:3000/test.html を要求します。表示されたフォームに、 適当に値を入力して Submit をクリックします。
すると Node 側 (サーバー側) では、次のようにフォームの内容が表示されます。
node test.js
Listening on http://localhost:3000/...
--- post() /foo called ---
--- req.body --
[Object: null prototype] {
country: 'United States',
city: 'Los Angeles'
}
--- req.files ---
[
{
fieldname: 'files',
originalname: 'image1.png',
encoding: '7bit',
mimetype: 'image/png',
destination: 'uploads/',
filename: 'd75b2f4e05d0afcae7f2fcd5e3e6b451',
path: 'uploads/d75b2f4e05d0afcae7f2fcd5e3e6b451',
size: 1465224
},
{
fieldname: 'files',
originalname: 'image2.png',
encoding: '7bit',
mimetype: 'image/png',
destination: 'uploads/',
filename: 'eafa07c1b28f1dfda08d6edbd8bc4f3c',
path: 'uploads/eafa07c1b28f1dfda08d6edbd8bc4f3c',
size: 1945144
}
]
確かに、入力した文字列 (United States、 Los Angeles) やアップロードしたファイルの情報が確認でき、 uploads フォルダにファイルが作成されていることが確認できました。