Skip to main content

Session 07: Upload file with Multer

Multer là một thư viện Node.js được sử dụng để xử lý upload file. Nó tích hợp với Express.js để hỗ trợ việc upload file lên server, bao gồm tải lên và phân tích dữ liệu từ một form (chủ yếu là biểu mẫu HTML ô chọn file). Multer cũng cung cấp một API để xử lý các tệp tải lên và lưu chúng vào cơ sở dữ liệu hoặc thư mục để quản lý. Nó cũng có thể xử lý nhiều tệp trong một lần upload. Với Multer, bạn có thể đảm bảo rằng tệp tải lên của bạn sẽ đạt được tính bảo mật cao và chỉ định các giới hạn về kích thước file, dung lượng file và loại file được tải lên.

Package

Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. It is written on top of busboy for maximum efficiency.

https://www.npmjs.com/package/multer

Install

npm install multer --save

Configuration

Middleware
const multer = require('multer');
const { updateDocument, findDocument } = require('../helpers/MongoDbHelper');

const UPLOAD_DIRECTORY = './public/uploads';

var upload = multer({
storage: multer.diskStorage({
contentType: multer.AUTO_CONTENT_TYPE,
destination: function (req, file, callback) {
const { id, collectionName } = req.params;

const PATH = `${UPLOAD_DIRECTORY}/${collectionName}/${id}`;
// console.log('PATH', PATH);
if (!fs.existsSync(PATH)) {
// Create a directory
fs.mkdirSync(PATH, { recursive: true });
}
callback(null, PATH);
},
filename: function (req, file, callback) {
// Xử lý tên file cho chuẩn
const safeFileName = toSafeFileName(file.originalname);
// return
callback(null, safeFileName);
},
}),
}).single('file');
Apply to route
// http://127.0.0.1:9000/upload/categories/63293fea50d2f78624e0c6f3/image
router.post('/:collectionName/:id/image', async (req, res, next) => {
const { collectionName, id } = req.params;

const found = await findDocument(id, collectionName);
if (!found) {
return res.status(410).json({ message: `${collectionName} with id ${id} not found` });
}

upload(req, res, async (err) => {
if (err instanceof multer.MulterError) {
res.status(500).json({ type: 'MulterError', err: err });
} else if (err) {
res.status(500).json({ type: 'UnknownError', err: err });
} else {
// UPDATE MONGODB
updateDocument(id, { imageUrl: `/uploads/${collectionName}/${id}/${req.file.filename}` }, collectionName);
//
// console.log('host', req.get('host'));
const publicUrl = `${req.protocol}://${req.get('host')}/uploads/${collectionName}/${id}/${req.file.filename}`;
res.status(200).json({ ok: true, publicUrl: publicUrl });
}
});
});
Upload with HTML form
<form enctype="multipart/form-data" action="http://127.0.0.1:9000/upload/products/6364fbbfeac7fb67de0dbf1b" method="post">
<input type="file" name="file" />
<input type="text" name="name" />
<input type="text" name="description" />
<input type="submit" value="Upload" name="submit" />
</form>
Upload with Antd
import React from 'react';
import { Layout, message, Upload, Button } from 'antd';
import { Content } from 'antd/lib/layout/layout';
import { UploadOutlined } from '@ant-design/icons';

export default function AntUpload() {
return (
<Layout>
<Content style={{ padding: 12 }}>
<Upload
showUploadList={false}
name='file'
data={{ name: 'Hello ANTD', description: 'Mô tả ANTD' }}
action='http://127.0.0.1:9000/upload/categories/631731e0f4368ae8174a1a67'
headers={{ authorization: 'authorization-text' }}
onChange={(info) => {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}

if (info.file.status === 'done') {
message.success(`${info.file.name} file uploaded successfully`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} file upload failed.`);
}
}}
>
<Button icon={<UploadOutlined />}>Click to Upload</Button>
</Upload>
</Content>
</Layout>
);
}
Upload with Antd (Manual)
import React from 'react';
import { Layout, message, Upload, Button } from 'antd';
import { Content } from 'antd/lib/layout/layout';
import { UploadOutlined } from '@ant-design/icons';
import axios from 'axios';

export default function ManualAntUpload() {
const [file, setFile] = React.useState(null);

return (
<Layout>
<Content style={{ padding: 12 }}>
<Upload
showUploadList={true}
beforeUpload={(file) => {
setFile(file);
return false;
}}
>
<Button icon={<UploadOutlined />}>Click to Upload</Button>
</Upload>

<Button
onClick={() => {
const formData = new FormData();
formData.append('file', file);
formData.append('name', 'Category 1234');
formData.append('description', 'Mo ta 1234');

axios.post('http://127.0.0.1:9000/upload/categories/631731e0f4368ae8174a1a67', formData).then((respose) => {
console.log(respose.data);
});
}}
>
Submit
</Button>
</Content>
</Layout>
);
}