Trong bài trước chúng ta tìm hiểu express, một thư viện tương đối nhỏ gọn cho http server, trong bài này chúng ta sẽ cùng nhau cài đặt api upload file kinh điển với thư viện multer nhé.

Multer

Multer là một phần mềm trung gian (middleware) node.js để xử lý multipart/form-data, chủ yếu được sử dụng cho upload file. Bạn có thể tìm hiểu thêm về multer tại đây.

Khởi tạo dự án

Chúng ta có thể khởi tạo một thư mục có tên upload-file và một tập tin main.js bên trong.

Khai báo các phụ thuộc

Chúng ta sẽ khai báo các phụ thuộc là express và multer như sau:

const express = require("express");
const multer  = require("multer");

Khai báo các dữ liệu điều kiện

Chúng ta sẽ chỉ cho phép một số loại tập tin được tải lên máy chủ để tăng cường độ bảo mật, ví dụ ở đây chúng ta sẽ cho phép hai loại tập tin là ảnh jpg và png, chúng ta sẽ khai báo các cấu hình như sau:

// danh sách các kiểu mimetype được phép tải lên
const acceptedMimeTypes = [
    "image/jpeg",
    "image/png"
];

// ánh xạ giữa mimetype và phần mở rộng tập tin.
const extensionByMimeType = {
    "image/jpeg": "jpg",
    "image/png": "png"
};

Trong dự án thực tế, chúng ta sẽ thường lưu các cấu hình này trong cơ sở dữ liệu để thay đổi dễ dàng mà không phải khởi động lại máy chủ.
Ở đây chúng ta có một khái niệm, mimetype, nếu bạn chưa biết nó là gì, bạn có thể tìm hiểu nó ở đây.

Khai báo hàm lọc và lưu trữ

Một tập tin muốn được tải lên máy chủ thành công và được lưu trữ sẽ cần trải qua các bước sau:

Vậy nên chúng ta sẽ cần khởi tạo một hàm để lọc tập tin như sau:

const filter = function (req, file, cb) {
    const mimetype = file.mimetype;
    console.log("file.mimetype:", mimetype);
    if (acceptedMimeTypes.indexOf(mimetype) < 0) {
        return cb(new multer.MulterError("Invalid file type"));
    }
    cb(null,true);
};

Hàm này sẽ kiểm tra mimetype của tập tin, nếu nằm trogn danh sách các mimetype hợp lệ sẽ được đi tiếp, ngược lại sẽ ném ra lỗi.
Tiếp theo chúng ta sẽ khởi tạo một đối tượng lưu trữ như sau:

const storage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, "files/")
    },
    filename: function (req, file, cb) {
      const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1E9);
      const mimetype = file.mimetype;
      const fileName = file.fieldname + "-" + uniqueSuffix + "." + extensionByMimeType[mimetype];
      cb(null, fileName)
    }
});

Đối tượng này chứa hai hàm:

  1. Destination: Để chỉ định thư mục lưu trữ tập tin.
  2. Filename: Để tạo ra tên mới cho tập tin để lưu trữ.

Mã nguồn xử lý

Để có thể xử lý yêu cầu tải tập tin lên máy chủ, chúng ta có thể đăng ký một API /upload với mã nguồn như sau:

const upload = multer({
    storage: storage,
    fileFilter: filter
});

const app = express()

const singleton = upload.single('file');
app.post('/upload', function (req, res, next) {
    singleton(req, res, function (err) {
        if (err instanceof multer.MulterError) {
            res.status(400).send(err);
        } else if (err) {
            res.status(500).send(err);
        } else {
            res.send("OK");
        }
    })
});

API này xử lý một file được tải lên, nếu có lỗi liên quan đến multer thì trả về trạng thái 400 (bad request), nếu có lỗi bất thường thì trả về trạng thái 500 (internal server error), nếu không có lỗi thì trả về thông điệp “OK”.

Tích hợp mã nguồn

Chúng ta có thể tích hợp tất cả các mã nguồn lại với nhau như sau:

const express = require("express");
const multer  = require("multer");

const acceptedMimeTypes = [
    "image/jpeg",
    "image/png"
];

const extensionByMimeType = {
    "image/jpeg": "jpg",
    "image/png": "png"
};

const filter = function (req, file, cb) {
    const mimetype = file.mimetype;
    console.log("file.mimetype:", mimetype);
    if (acceptedMimeTypes.indexOf(mimetype) < 0) {
        return cb(new multer.MulterError("Invalid file type"));
    }
    cb(null,true);
};

const storage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, "files/")
    },
    filename: function (req, file, cb) {
      const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1E9);
      const mimetype = file.mimetype;
      const fileName = file.fieldname + "-" + uniqueSuffix + "." + extensionByMimeType[mimetype];
      cb(null, fileName)
    }
});

const upload = multer({
    storage: storage,
    fileFilter: filter
});

const app = express()

const singleton = upload.single('file');
app.post('/upload', function (req, res, next) {
    singleton(req, res, function (err) {
        if (err instanceof multer.MulterError) {
            res.status(400).send(err);
        } else if (err) {
            res.status(500).send(err);
        } else {
            res.send("OK");
        }
    })
});

const port = 3000;
app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
});

Ở đây chúng chúng ta sẽ khởi chạy một http server lắng nghe cổng 3000 với một API /upload duy nhất.

Khởi chạy

Chúng ta có thể khởi chạy dự án thông qua lệnh: node main.js sau đó chúng ta có thể sử dụng Postman để kiểm thử, ví dụ cho 2 trường hợp tập tin không hợp lệ và hợp lệ:

Tổng kết

Như vậy chúng ta đã cùng nhau tạo một API để upload file với express và multer.


Cám ơn bạn đã quan tâm đến bài viết|video này. Để nhận được thêm các kiến thức bổ ích bạn có thể:

  1. Đọc các bài viết của TechMaster trên facebook: https://www.facebook.com/techmastervn
  2. Xem các video của TechMaster qua Youtube: https://www.youtube.com/@TechMasterVietnam nếu bạn thấy video/bài viết hay bạn có thể theo dõi kênh của TechMaster để nhận được thông báo về các video mới nhất nhé.
  3. Chat với techmaster qua Discord: https://discord.gg/yQjRTFXb7a