フォームからアップロードされたファイルを 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 StatesLos Angeles) やアップロードしたファイルの情報が確認でき、 uploads フォルダにファイルが作成されていることが確認できました。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Node.js 入門