はいさい、ちゅらデータぬオースティンやいびーん!んな、がんじゅー?(みんな、元気?)
概要
本記事では、Node.jsのexpressフレームワークで、multerというミドルウェアを使って、FormDataからファイルを取って、アップロード機能をバックエンドに追加する方法を紹介します。
事前準備
Node.jsのローカルインストール
目次
- Expressのセットアップ
- <form>の作成
- 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
が出来上がります!
{
"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を作成し、設定を入れます。筆者の推奨設定は以下の通りです。
{
"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
を置きます。
そこに以下のように基本的なロジックを入れます。
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で指定しているのですが、それを作っていないので、作っておきましょう。
ここに、ファイルをアップロードするフォームも入れます。
<!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!
また、ページをアクセスしてみると以下のような画面が出るはず!
これでmulter
の説明に入りましょう!
multer
の導入
ここから、multer
の使い方を解説していきます。
multer
のパッケージを追加する
まずは、multerとTypeScriptの関連型をインストールします。
先ほど動かしたサーバーを一旦止めましょう。
yarn add multer
yarn add -D @types/multer
これで、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
の定数を使います。
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));
試してみよう、アップロード!
またサーバーを立ち上げて、何かをアップロードしてみましょう!
ばっちり!
まとめ
これでmulterを使ってFormDataについているファイルの処理をする方法を紹介しましたが、いかがでしょうか?
次の記事では、アップロードされたファイルに対して、child_process
を用いて、何らかの処理を施す方法を紹介します!