multerを使ってNode.js+Expressでファイルアップロードを実装する

ExpressのWebサーバで、multerを使い、クライアントからアップロードされたファイルを受信する方法です。

インストール

npm install multer

単一ファイル

サーバ側

multer.single()で受け取ります。single()のパラメータはFormのフィールド名です。

const multer = require('multer');

app.post('/upload-file', multer({ dest: './upload' }).single('field_file'), (request, response) => {
    console.log(request.file);

    try {
        console.log(request.file.path);
        response.sendStatus(200);
    } catch (err) {
        console.error(err);
        response.sendStatus(500);
    }
});

クライアント側

クライアント側はHTMLのFormのみで送信する方法と、JavaScriptを使って送信する方法があります。

HTMLのみ

<form action="/upload-file" method="post" enctype="multipart/form-data">
    <div class="input-group">
        <input type="file" name="field_file" accept=".txt" class="form-control">
        <button type="submit" class="btn btn-primary">アップロード</button>
    </div>
</form>

HTML&スクリプト

HTML
<div class="input-group">
    <input type="file" id="uploadFile" accept=".txt" class="form-control">
    <button type="button" class="btn btn-primary" onclick="sendFile();">アップロード</button>
</div>
スクリプト
function sendFile() {
    const input = document.querySelector("#uploadFile");
    const formData = new FormData();
    formData.append('field_file', input.files[0]);

    fetch('/upload-file', {
        method: 'POST',
        body: formData,
    }).then(response => {
        if (!response.ok) {
            throw('ファイルのアップロードに失敗しました');
        }
        alert("アップロードしました")
    }).catch((error) => {
        alert(error);
    });
}

アップロード時のサーバ側ログ

{
  fieldname: 'field_file',
  originalname: 'sample1.txt',
  encoding: '7bit',
  mimetype: 'text/plain',
  destination: './upload',
  filename: '52b29053a31243a768a32c1ec197ce2a',
  path: 'upload/52b29053a31243a768a32c1ec197ce2a',
  size: 4
}

単一フィールドからの複数ファイルをアップロード

サーバ側

multer.array()で受け取ります。array()のパラメータはFormのフィールド名と最大ファイル数です。

app.post('/upload-file/multi', multer({ dest: './upload' }).array('field_files', 2), (request, response) => {
    console.log(request.files);
    console.log(request.files[0].path);
    console.log(request.files[1].path);
    response.sendStatus(200);
});

クライアント側

HTMLのみ

<form action="/upload-file/multi" method="post" enctype="multipart/form-data">
    <div class="input-group">
        <input type="file" name="field_files" accept=".txt" multiple class="form-control">
        <button type="submit" class="btn btn-primary">アップロード</button>
    </div>
</form>

HTML&スクリプト1

HTML
<input type="file" id="uploadFiles" accept=".txt" multiple class="form-control">
<button type="button" class="btn btn-primary" onclick="sendFiles();">アップロード</button>
スクリプト
function sendFiles() {
    const input = document.querySelector("#uploadFiles");
    const formData = new FormData();
    formData.append('field_files', input.files[0]);
    formData.append('field_files', input.files[1]);
    fetch('/upload-file/multi', {
        method: 'POST',
        body: formData,
    }).then(response => {
        if (!response.ok) {
            throw('ファイルのアップロードに失敗しました');
        }
        alert("アップロードしました")
    }).catch((error) => {
        alert(error);
    });
}

HTML&スクリプト2

画面上は2つのinputフィールドを用意し、スクリプトで1つのフォームデータとして送信する方法です。

HTML
<input type="file" id="uploadFiles1" accept=".txt" class="form-control">
<input type="file" id="uploadFiles2" accept=".txt" class="form-control">
<button type="button" class="btn btn-primary" onclick="sendFiles();">アップロード</button>
スクリプト
function sendFiles() {
    const input1 = document.querySelector("#uploadFiles1");
    const input2 = document.querySelector("#uploadFiles2");
    const formData = new FormData();
    formData.append('field_files', input1.files[0]);
    formData.append('field_files', input2.files[0]);
    fetch('/upload-file/multi', {
        method: 'POST',
        body: formData,
    }).then(response => {
        if (!response.ok) {
            throw('ファイルのアップロードに失敗しました');
        }
        alert("アップロードしました")
    }).catch((error) => {
        alert(error);
    });
}

アップロード時のサーバ側ログ

[
  {
    fieldname: 'field_files',
    originalname: 'sample1.txt',
    encoding: '7bit',
    mimetype: 'text/plain',
    destination: './upload',
    filename: 'aad7d8e4f0ac4fc0ecb66d53762321d4',
    path: 'upload/aad7d8e4f0ac4fc0ecb66d53762321d4',
    size: 4
  },
  {
    fieldname: 'field_files',
    originalname: 'sample2.txt',
    encoding: '7bit',
    mimetype: 'text/plain',
    destination: './upload',
    filename: 'bb16d87ef2bff538d9b0f89d8268dadb',
    path: 'upload/bb16d87ef2bff538d9b0f89d8268dadb',
    size: 18
  }
]

複数フィールドからファイルをアップロード

サーバ側

multer.fields()で受け取ります。fields()の各要素のnameプロパティがFormのフィールド名です。

app.post('/upload-file/multi-input', multer({ dest: './upload' }).fields([
        { name:'field_file1', maxCount:1 },
        { name:'field_file2', maxCount:1 }
    ]), (request, response) => {
    console.log(request.files);
    console.log(request.files['field_file1'][0].path);
    console.log(request.files['field_file2'][0].path);
    response.sendStatus(200);
});

クライアント側

HTMLのみ

<form action="/upload-file/multi-input" method="post" enctype="multipart/form-data">
    <div class="input-group">
        <input type="file" name="field_file1" accept=".txt" class="form-control">
        <input type="file" name="field_file2" accept=".txt" class="form-control">
        <button type="submit" class="btn btn-primary">アップロード</button>
    </div>
</form>

HTML&スクリプト

HTML
<input type="file" id="uploadFile1" accept=".txt" class="form-control">
<input type="file" id="uploadFile2" accept=".txt" class="form-control">
<button type="button" class="btn btn-primary" onclick="sendFiles2();">アップロード</button>
スクリプト
function sendFiles2() {
    const input1 = document.querySelector("#uploadFile1");
    const input2 = document.querySelector("#uploadFile2");
    const formData = new FormData();
    formData.append('field_file1', input1.files[0]);
    formData.append('field_file2', input2.files[0]);
    fetch('/upload-file/multi-input', {
        method: 'POST',
        body: formData,
    }).then(response => {
        if (!response.ok) {
            throw('ファイルのアップロードに失敗しました');
        }
        alert("アップロードしました")
    }).catch((error) => {
        alert(error);
    });
}

アップロード時のサーバ側ログ

[Object: null prototype] {
  field_file1: [
    {
      fieldname: 'field_file1',
      originalname: 'sample1.txt',
      encoding: '7bit',
      mimetype: 'text/plain',
      destination: './upload',
      filename: '10b77b3a2f139e0c9313ff606e8bf715',
      path: 'upload/10b77b3a2f139e0c9313ff606e8bf715',
      size: 4
    }
  ],
  field_file2: [
    {
      fieldname: 'field_file2',
      originalname: 'sample2.txt',
      encoding: '7bit',
      mimetype: 'text/plain',
      destination: './upload',
      filename: '3095e282680e22bca2dc40c3976e4214',
      path: 'upload/3095e282680e22bca2dc40c3976e4214',
      size: 18
    }
  ]
}
このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

コメント

メールアドレスが公開されることはありません。 が付いている欄は必須項目です