LoginSignup
10
4

More than 1 year has passed since last update.

Node.js・Expressでmulterを使って、ファイルをアップロードする方法

Last updated at Posted at 2022-07-12

はいさい、ちゅらデータぬオースティンやいびーん!んな、がんじゅー?(みんな、元気?)

概要

本記事では、Node.jsのexpressフレームワークで、multerというミドルウェアを使って、FormDataからファイルを取って、アップロード機能をバックエンドに追加する方法を紹介します。

事前準備

Node.jsのローカルインストール

目次

  1. Expressのセットアップ
  2. <form>の作成
  3. multerの導入

Expressのセットアップ

パッケージをインストールする

今回は、TypeScriptを使ったExpressプロジェクトを元に作っていくので、まずは、新規フォルダーを作って、package.jsonを作ります。

また、筆者はyarn推奨派なので、全てのコマンドはyarnを使います。

mkdir express-multer-upload
cd express-multer-upload
yarn init
yarn add express body-parser
yarn add -D typescript @types/express @types/node nodemon ts-node

すると、以下のようなpackage.jsonが出来上がります!

package.json
{
  "name": "express-multer-upload",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "body-parser": "^1.20.0",
    "express": "^4.18.1"
  },
  "devDependencies": {
    "@types/express": "^4.17.13",
    "@types/node": "^18.0.3",
    "nodemon": "^2.0.19",
    "ts-node": "^10.8.2",
    "typescript": "^4.7.4"
  }
}

そこに、以下のscriptsコマンドを入れます。

...
  "scripts": {
    "dev": "nodemon src/index.ts"
  }
}

TypeScriptの設定

次は、tsconfig.jsonを作成し、設定を入れます。筆者の推奨設定は以下の通りです。

tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "target": "esnext",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "sourceMap": true,
    "outDir": "dist",
    "allowJs": true,
    "lib": ["dom", "es6"],
    "baseUrl": "./src",
  },
  "exclude": ["node_modules", "dist"],
  "include": ["src/**/*.ts"],
}

src/index.tsを作成し、expressの基本ロジックを入れる

そして、srcのフォルダーを作り、そこにindex.tsを置きます。

そこに以下のように基本的なロジックを入れます。

src/index.ts
import bodyParser from "body-parser";
import express from "express";
import { createServer } from "http";
import path from "path";

const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use("/public", express.static(path.resolve(__dirname, "../public")));

app.get("/", (req, res) => {
  res.sendFile(path.join(__dirname, "index.html"));
});

app.post("/", (req, res) => {
  res.redirect("/");
});

const server = createServer(app);
const port = 4000;
server.listen(port, () => console.log("Listening on port: ", port));

これでExpressの基本的なセットアップはOKです!

index.htmlと<form>の作成

index.htmlをGETで指定しているのですが、それを作っていないので、作っておきましょう。

ここに、ファイルをアップロードするフォームも入れます。

public/index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Express Multer Uploads</title>
</head>

<body>
  <style>
    form {
      display: flex;
      flex-direction: column;
      max-width: 500px;
      margin: 1rem auto;
    }
    input {
      margin-bottom: 1rem;
    }
  </style>
  <h1>Express Multer Uploads!</h1>
  <form action="/" method="POST" enctype="multipart/form-data">
    <label for="name">Name</label>
    <input type="text" name="name" id="name" minlength="1" maxlength="64" required>
    <label for="file">File</label>
    <input type="file" name="file" id="file" accept="video/mp4 image/png image/jpeg audio/mpeg">
    <button type="submit">Send</button>
  </form>
</body>

</html>

<form>には必ず、enctype="multipart/form-data"を入れるようにしましょう!こうしないと、multerは拾ってくれません。

また、<input type="file">に、アップロードしてもいいファイルのMIMEタイプを指定しています。これはmulterでも指定します。

試してみよう!

ここまでの作業がうまくいったのか、確認してみましょう。

ターミナルで以下のコードを実行して、expressを立ち上げます。

yarn dev

ターミナルに以下のような出力があったらOK!
スクリーンショット 2022-07-12 10.18.57.png
また、ページをアクセスしてみると以下のような画面が出るはず!
スクリーンショット 2022-07-12 10.19.41.png
これでmulterの説明に入りましょう!

multerの導入

ここから、multerの使い方を解説していきます。

multerのパッケージを追加する

まずは、multerとTypeScriptの関連型をインストールします。

先ほど動かしたサーバーを一旦止めましょう。

yarn add multer
yarn add -D @types/multer

これで、package.jsonは以下のようになります。

package.json
{
  "name": "express-multer-upload",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "body-parser": "^1.20.0",
    "express": "^4.18.1",
    "multer": "^1.4.5-lts.1"
  },
  "devDependencies": {
    "@types/express": "^4.17.13",
    "@types/multer": "^1.4.7",
    "@types/node": "^18.0.3",
    "nodemon": "^2.0.19",
    "ts-node": "^10.8.2",
    "typescript": "^4.7.4"
  },
  "scripts": {
    "dev": "nodemon src/index.ts"
  }
}

multerの設定を追加する

次は、expressでmulterを読み込み、設定します。

diskStorageでサーバー上の保存設定を決める

最初に、multerがFormDataからファイルを受け取った時に、サーバーのどこにそれを保存すればいいかの設定を持つstorageという定数を作ります。

import multer from "multer";

const storage = multer.diskStorage({
  destination(req, file, callback) {
    callback(null, path.resolve(__dirname, "../uploads"));
  },
  filename(req, file, callback) {
    const uniqueSuffix = Math.random().toString(26).substring(4, 10);
    callback(null, `${Date.now()}-${uniqueSuffix}-${file.originalname}`);
  },
});

ここでサーバー上の/uploadsというフォルダーに、アップロードされたファイルにアップロードされた時間と元々付いていた名前を使って保存するように指定しています。

/uploadsフォルダーがなかったら、multerは作ってくれます。

multerの初期設定

次は上記のstorage定数も使って、multerのインスタンスを作ります。

const upload = multer({
  storage,
  fileFilter(req, file, callback) {
    console.log(file.mimetype)
    if (["video/mp4", "image/png", "image/jpeg", "audio/mpeg"].includes(file.mimetype)) {
      callback(null, true);
      return;
    }
    callback(new TypeError("Invalid File Type"));
  },
});

fileFilterでは、ファイルのMIMEタイプを見て、アップロードしてもいいものかどうかを判断しています。ここで、もっと厳しいチェックをすることもできます。

実際、MIMEタイプを偽ることができるので、セキュリティ上、MIMEタイプのみに頼るのはお勧めしません。

ミドルウェアとして、指定のパスにmulterを使う

最後に、ファイルのアップロードをさせたいパスに、上記のuploadの定数を使います。

src/index.ts
import bodyParser from "body-parser";
import express from "express";
import { createServer } from "http";
import path from "path";
import multer from "multer";

const storage = multer.diskStorage({
  destination(req, file, callback) {
    callback(null, path.resolve(__dirname, "../uploads"));
  },
  filename(req, file, callback) {
    const uniqueSuffix = Math.random().toString(26).substring(4, 10);
    callback(null, `${Date.now()}-${uniqueSuffix}-${file.originalname}`);
  },
});

const upload = multer({
  storage,
  fileFilter(req, file, callback) {
    console.log(file.mimetype)
    if (["video/mp4", "image/png", "image/jpeg", "audio/mpeg"].includes(file.mimetype)) {
      callback(null, true);
      return;
    }
    callback(new TypeError("Invalid File Type"));
  },
});

const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use("/public", express.static(path.resolve(__dirname, "../public")));

app.get("/", (req, res) => {
  res.sendFile(path.join(__dirname, "index.html"));
});

// "file"とは、<input name="file">の"file"というフィールド名に当たります
app.post("/", upload.single("file"), (req, res) => {
  console.log(req.file);
  res.redirect("/");
});

const server = createServer(app);
const port = 4000;
server.listen(port, () => console.log("Listening on port: ", port));

試してみよう、アップロード!

またサーバーを立ち上げて、何かをアップロードしてみましょう!
ezgif.com-gif-maker (8).gif
ばっちり!

まとめ

これでmulterを使ってFormDataについているファイルの処理をする方法を紹介しましたが、いかがでしょうか?

次の記事では、アップロードされたファイルに対して、child_processを用いて、何らかの処理を施す方法を紹介します!

10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4