Trung Quân
  • Node.js
  • ReactJS
    • Learn React Hooks
  • MERN Stack
  • Thuật Toán
  • Công Nghệ
    • Amazon AWS
    • Hosting – Domain
  • Về Tác Giả
  • Bản Quyền
Top Posts
Lộ trình học lập trình Web từ con...
Nhận diện, xác thực khuôn mặt với ReactJS...
Tạo hiệu ứng thẻ bài Magic với HTML...
NodeJS viết API gửi Email với OAuth2 và...
Tạo hiệu ứng Parallax đơn giản chỉ với...
Git – GitHub • Học Git thực tế...
Tạo một trang GitHub Profile phiên bản vũ...
Cài đặt iTerm2, Oh My Zsh, Zsh-autosuggestions và...
Cài đặt NVM, NodeJS và GIT trên MacOS...
Thuật toán Tìm phần tử bị lặp đầu...

Trung Quân

  • Node.js
  • ReactJS
    • Learn React Hooks
  • MERN Stack
  • Thuật Toán
  • Công Nghệ
    • Amazon AWS
    • Hosting – Domain
  • Về Tác Giả
  • Bản Quyền
Node.js

Upload file trong Node.js?

by trungquandev March 12, 2019
written by trungquandev March 12, 2019
nodejs-upload-files-trungquandev

Xin chào tất cả các bạn, mình là Quân, tiếp tục series về Node.js, hôm nay chúng ta sẽ cùng nhau đi tìm hiểu hai cách để upload files trong ứng dụng Node.js nhé.

“Bài này thuộc bài số 06 trong loạt bài Lập Trình Nodejs Cơ Bản.“

Những nội dung có trong bài:

  1. Tạo sẵn giao diện Form Upload
  2. Xử lý Upload file với Formidable
  3. Xử lý Upload file với Multer
  4. Full source code trên github

1. Tạo sẵn giao diện Form Upload

Phần này vì mình đã hướng dẫn ở bài Tìm hiểu 3 Modules Built-in trong Node.js: HTTP – URL – File System nên mình sẽ không giải thích nhiều mà paste code vào luôn thôi nhé:

Cấu trúc thư mục ứng dụng như sau:

uploads

views

master.html

package.json

server.js

  • Nội dung file server.js
/**
 * Created by trungquandev.com's author on 10/03/2019.
 * server.js
 */
 
let http = require("http");
let url = require("url");
let fs = require("fs");
 
let server = http.createServer((req, res) => {
    let urlData = url.parse(req.url, true);
    let fileName = "./views" + urlData.pathname;
 
    if(urlData.pathname === "/") {
        fileName = "./views/master.html";
    }
 
    fs.readFile(fileName, (err, data) => {
        if(err) {
            console.log(err);
            res.writeHead(404, {"Content-Type": "text/html"});
            res.write("404 Not Found");
 
            return res.end();
        }
        res.writeHead(200, {"Content-Type": "text/html"});
        res.write(data);
 
        return res.end();
    });
});
 
server.listen(8017, "localhost", () => {
  console.log(`Hello Trung Quan, I'm running at localhost:8017/`);
});
  • Nội dung file master.html
<!--
* Created by trungquandev.com's author on 10/03/2019.
*/
// views/master.html
-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="shortcut icon" href="https://trungquandev.com/wp-content/uploads/2016/11/LOGO.png" />
    <title>Node.js upload files</title>

    <!-- Get bootstrap from CDN-->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-sm-8">
                <br>
                <h4>
                    Node.js upload files - trungquandev
                </h4>
                <div class=""></div>
                <form action="/upload" method="POST" enctype="multipart/form-data">
                    <div class="form-group">
                        <label for="example-input-file">&nbsp;</label>
                        <input type="file" name="file" class="form-control-file border">
                    </div>
                    <button type="submit" class="btn btn-primary">Submit</button>
                </form>
            </div>
        </div>
    </div>
</body>
</html>

“Lưu ý là trong thẻ <form> ở trên phải có một thuộc tính là enctype=”multipart/form-data” và thẻ <input> phải có một cái name ví dụ như name=”file” ở trên nhé.”

Kết quả sau khi chạy ứng dụng: node server.js

nodejs-upload-files-trungquandev-01

2. Xử lý Upload file với Formidable

Nói qua về thằng này một chút, mình trích lời giới thiệu chính thức của Formidable thì nó là một module giúp chúng ta phân tích dữ liệu biểu mẫu, đặc biệt là tập trung vào việc encoding các hình ảnh và video, hay nói dễ hiểu và ngắn gọn hơn là tập trung vào việc tải lên các tệp tin.

Một số tính năng mà module này liệt kê ra như sau:

  • Non-buffering multipart parser: Tốc độ cao, lên tới xấp xỉ 500mb/giây và không cần bộ nhớ đệm cho việc phân tích cú pháp.
  • Automatically writing file uploads to disk: Tự động ghi lại các tập tin tải lên.
  • Graceful error handling: Cú pháp bắt lỗi & xử lý lỗi dễ dàng. 
  • Low memory footprint: Có thể hiểu đơn giản là thư viện này ăn ít Ram.
  • Very high test coverage: Thư viện này đã được viết test rất cẩn thận (theo như chúng nó nói =))

Rồi, xem qua lý thuyết như vậy thôi, mình sẽ bắt đầu triển khai một ví dụ để các bạn biết cách dùng module này cho việc upload nhé:

“Cụ thể hơn, trong ví dụ dưới đây, mình sẽ sử dụng các module http-fs-url để tạo server, và kết hợp dùng formidable để xử lý upload file. Chưa dùng framework express.js nhé, express.js để phần 3 mình sẽ làm ví dụ với multer.”

Cài đặt module: npm install --save formidable hoặc npm i -S formidable

Ở file server.js có 2 việc cần làm:

  • Việc đầu tiên là chúng ta nạp module formidable:
  • Việc thứ hai là viết thêm một đoạn code kiểm tra điều kiện upload file bên trong function createServer()…

– Nội dung file server.js sau khi thay đổi như sau (mình đã comment giải thích rõ ràng những đoạn code mới thêm vào rồi nha)

/**
 * Created by trungquandev.com's author on 10/03/2019.
 * server.js
 */

let http = require("http");
let url = require("url");
let fs = require("fs");
let formidable = require("formidable");
 
let server = http.createServer((req, res) => {
    // Kiểm tra nếu như url truyền lên là /upload và phương thức là post
    if (req.url == "/upload" && req.method.toLowerCase() == "post") {
      // Khởi tạo biến form bằng IncomingForm để phân tích một tập tin tải lên
      let form = new formidable.IncomingForm();

      // Cấu hình thư mục sẽ chứa file trên server với hàm .uploadDir
      form.uploadDir = "uploads/"

      // Xử lý upload file với hàm .parse
      form.parse(req, (err, fields, files) => {
        if (err) throw err;
        // Lấy ra đường dẫn tạm của tệp tin trên server
        let tmpPath = files.file.path;
        // Khởi tạo đường dẫn mới, mục đích để lưu file vào thư mục uploads của chúng ta
        let newPath = form.uploadDir + files.file.name;
        // Đổi tên của file tạm thành tên mới và lưu lại
        fs.rename(tmpPath, newPath, (err) => {
          if (err) throw err;
          
          switch (files.file.type) {
            // Kiểm tra nếu như là file ảnh thì render ảnh và hiển thị lên.
            case "image/jpeg":
              fs.readFile(newPath, (err, fileUploaded) => {
                res.writeHead(200,{"Content-type":"image/jpeg"});
                res.end(fileUploaded);
              });
              break;
            // Còn lại các loại file khác thì chỉ hiển thị nội dung thông báo upload thành công.
            default:
              res.writeHead(200, {"Content-Type": "text/html"});
              res.end(`Upload file <strong>${files.file.name}</strong> successfuly`);
              break;
          }
        });
      });

      // Return ở đây để code không chạy tiếp xuống dưới
      return;
    }

    // Nếu không phải action upload thì trả về client cái form upload
    let urlData = url.parse(req.url, true);
    let fileName = "./views" + urlData.pathname;
    if(urlData.pathname === "/") {
        fileName = "./views/master.html";
    }
    fs.readFile(fileName, (err, data) => {
      if(err) {
        console.log(err);
        res.writeHead(404, {"Content-Type": "text/html"});
        res.write("404 Not Found");
        return res.end();
      }
      res.writeHead(200, {"Content-Type": "text/html"});
      res.write(data);
      return res.end();
    });
});
 
server.listen(8017, "localhost", () => {
  console.log(`Hello Trung Quan, I'm running at localhost:8017/`);
});

Kết quả: Một bức tranh con mèo do mình vẽ, cho mình khoe chút =))))

Upload ảnh thành công:

nodejs-upload-files-trungquandev-02

Upload tệp tin trungquandev.txt thành công:

nodejs-upload-files-trungquandev-03

Kiểm tra trong thư mục:

nodejs-upload-files-trungquandev-04

Ngoài ra module này mở rộng thêm nhiều tính năng nữa ví dụ như giới hạn kích thước file tải lên form.maxFileSize…vv, thì có thể xem thêm ở đây nhé: Formidable – npm


3. Xử lý Upload file với Multer

Multer cũng là một module khá nổi tiếng, tuy lượt dowload hàng tuần rất khiêm tốn là (421,391 lượt) thấp hơn so với formidable (2,206,310 lượt) nhưng đổi lại thì số star trên repo github của nó lại cao hơn (6192 star) so với (4849 star) của formidable.
“Lưu ý số liệu này là tính đến thời điểm hiện tại mình viết bài, sau này có thể sẽ khác.”

Một điểm cộng nữa là Multer có thể sử dụng dễ dàng như một middleware đối với một ứng dụng node.js chạy trên framework Express.js, chắc nhờ fame thằng Express này nên số star của nó cũng cao, bởi vì rất nhiều người mới đầu tiếp cận với node.js cũng đều học Express.js đầu tiên. (Mình là một điển hình 😀 )

Bây giờ mình sẽ làm ví dụ upload file sử dụng kết hợp Multer và Express.js nhé.
(Dĩ nhiên là các bạn cũng có thể kết hợp Formidable với Express.js hay là Multer với http-fs-url như ở phần 2 nhé, cần support thì cứ thoải mái comment hỏi mình 😀 )

Trước tiên, các bạn cài cho mình 2 thằng express và multer:

npm install --save express

npm install --save multer

Ngoài ra mình có sử dụng thêm một module tích hợp sẵn trong node.js là “path” để lấy đường dẫn gốc của thư mục.
Cụ thể, chúng ta sẽ viết lại file server.js như sau:

/**
 * Created by trungquandev.com's author on 11/03/2019.
 * server.js
 */

let express = require("express");
let multer = require("multer");
let path = require("path");

let app = express();

// Route này trả về cái form upload cho client
app.get("/", (req, res) => {
  res.sendFile(path.join(`${__dirname}/views/master.html`));
});

// Khởi tạo biến cấu hình cho việc lưu trữ file upload
let diskStorage = multer.diskStorage({
  destination: (req, file, callback) => {
    // Định nghĩa nơi file upload sẽ được lưu lại
    callback(null, "uploads");
  },
  filename: (req, file, callback) => {
    // ở đây các bạn có thể làm bất kỳ điều gì với cái file nhé.
    // Mình ví dụ chỉ cho phép tải lên các loại ảnh png & jpg
    let math = ["image/png", "image/jpeg"];
    if (math.indexOf(file.mimetype) === -1) {
      let errorMess = `The file <strong>${file.originalname}</strong> is invalid. Only allowed to upload image jpeg or png.`;
      return callback(errorMess, null);
    }

    // Tên của file thì mình nối thêm một cái nhãn thời gian để đảm bảo không bị trùng.
    let filename = `${Date.now()}-trungquandev-${file.originalname}`;
    callback(null, filename);
  }
});

// Khởi tạo middleware uploadFile với cấu hình như ở trên,
// Bên trong hàm .single() truyền vào name của thẻ input, ở đây là "file"
let uploadFile = multer({storage: diskStorage}).single("file");

// Route này Xử lý khi client thực hiện hành động upload file
app.post("/upload", (req, res) => {
  // Thực hiện upload file, truyền vào 2 biến req và res
  uploadFile(req, res, (error) => {
    // Nếu có lỗi thì trả về lỗi cho client.
    // Ví dụ như upload một file không phải file ảnh theo như cấu hình của mình bên trên
    if (error) {
      return res.send(`Error when trying to upload: ${error}`);
    }
    // Không có lỗi thì lại render cái file ảnh về cho client.
    // Đồng thời file đã được lưu vào thư mục uploads
    res.sendFile(path.join(`${__dirname}/uploads/${req.file.filename}`));
  });
});
 
app.listen(8017, "localhost", () => {
  console.log(`Hello Trung Quan, I'm running at localhost:8017/`);
});

Kết quả:Khoe nốt một bức tranh mùa đông nữa của mình, đừng cười nhé =)))))

Upload thành công:

nodejs-upload-files-trungquandev-05

Khi upload lỗi:

nodejs-upload-files-trungquandev-06

Kiểm tra trong thư mục:

nodejs-upload-files-trungquandev-07

Các bạn cũng có thể đọc thêm về multer nhé, mình chỉ hướng dẫn cơ bản thôi, đi sâu vào nó còn nhiều tính năng hơn nữa ở đây:
https://www.npmjs.com/package/multer

4. Full source code trên github

Mình có để full source code của bài hôm nay ở repo này cho các bạn tham khảo nhé, nếu thấy bài viết bổ ích, hãy ủng hộ bằng cách cho mình 1 star trên repo này để mình có động lực tiếp tục viết những bài viết chất lượng nha, chân thành cảm ơn các bạn.
https://github.com/trungquandev/multer-nodejs-upload-file


Trên đây mình đã hướng dẫn upload file trong node.js bằng 2 cách, nhưng như các bạn thấy là chúng ta mới chỉ đang upload một lần một file thôi. Bài tiếp theo mình sẽ xử lý việc Upload nhiều file cùng lúc trong node.js nhé.

Xin chào và hẹn gặp lại các bạn ở những bài viết tiếp theo.

Best Regards – Trung Quân – Green Cat


Tham khảo kiến thức:

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

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

“Thanks for awesome knowledges.”

Khóa học lập trình làm việc thực tế:

Nếu các bạn thấy bài viết của mình có ích thì hãy ủng hộ mình bằng cách tham khảo bài viết giới thiệu khóa học lập trình MERN Stack Miễn Phí cực kỳ chất lượng và chính chủ dưới đây của mình nhé, cảm ơn các bạn ^^
KHOÁ HỌC LẬP TRÌNH MERN STACK 100% DỰ ÁN THỰC TẾ và CHẤT LƯỢNG
mern-stack-course-trungquandev
formidablemulternodejstrungquandevupload
2 comments
0
FacebookTwitterGoogle +Pinterest
trungquandev

previous post
Viết một CRUD API sử dụng Serverless Framework & DynamoDB
next post
Node.js & MongoDB – Xây dựng một ứng dụng Messenger trò chuyện trực tuyến.

Related Posts

Hướng dẫn sử dụng ES Modules – cú...

August 17, 2020

Gửi nhận email trong NodeJS cực kỳ đơn...

February 20, 2020

Upload multiple files trong NodeJS

August 18, 2019

NodeJS viết API gửi Email với OAuth2 và...

May 17, 2022

Hướng dẫn Loop through Object trong Javascript ES6

December 25, 2019

Xây dựng ứng dụng “động vật ẩn danh”...

January 15, 2018

“Module” trong Node.js, khái niệm và thực tiễn.

June 19, 2018

NodeJS triển khai xác thực 2 lớp Two-Factor...

August 17, 2020

Đào sâu một chút về module Events trong...

September 30, 2018

Node.js & MongoDB – Xây dựng một ứng...

May 26, 2019

Bát Chánh Đạo

batchanhdao-trungquandev

About Me

About Me

Trung Quân

Software Engineer at Pod Foods

Academy Of Cryptography Techniques

"I am a dog and cat lover, love green, love to read books, write blog and oil painting ..."

Read my CV → https://cv.trungquandev.com/

My Maxim Live

A bit of fragrance clings to the hand that gives flowers!

For Vietnamese young generation

Đừng bao giờ làm người khổng lồ trong tư tưởng nhưng chỉ là thằng lùn trong hành động.

Keep in touch

Facebook Instagram Linkedin Youtube Email Github

Fanpage Facebook

Facebook

Học lập trình “MERN Stack Cơ Bản” qua ứng dụng thực tế

mern-stack-trello-app-trungquandev


  Khóa học lập trình MERN Stack (NodeJS, ReactJS, ExpressJS, MongoDB) cực kỳ chất lượng và Miễn Phí do chính mình hướng dẫn nhé:
  MERN Stack - xây dựng ứng dụng quản lý công việc dạng Kanban tương tự Trello.

Học lập trình “MERN Stack Nâng Cao” qua ứng dụng thực tế

mern-stack-advanced-trello-app-trungquandev


  * Học lập trình MERN Stack Nâng Cao (NodeJS, ReactJS, ExpressJS, MongoDB). Đây là một khóa học mà mình đã làm cực kỳ tâm huyết, với phong cách dạy lập trình làm dự án thực tế, chuyên nghiệp. Để các bạn có một hành trang kiến thức vững chắc cho hành trình làm lập trình viên trong tương lai nhé.
  Lập Trình MERN Stack Nâng Cao - Học Thực Tế Để Đi Làm

YouTube: Trungquandev Official

youtube-channel-trungquandev-official


  - Các bạn tham khảo kênh YouTube chính thức của mình và ủng hộ mình bằng cách tặng mình một lượt Đăng Ký Kênh nha.
Cảm ơn các bạn ^^

  YouTube: TRUNGQUANDEV OFFICIAL

© Copyright

Bản quyền:
  © DMCA (Digital Millennium Copyright Act)


DMCA.com Protection Status

License

Giấy phép nội dung:
  Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 Quốc tế.


Giấy phép Creative Commons

Other links

Portfolio của mình:
  https://cv.trungquandev.com

Lập trình cuộc sống:
  https://laptrinhcuocsong.com

Nhiều bài viết hay về javascript:
  https://codetheworld.io

  • Facebook
  • Youtube
  • GitHub
  • Linkedin
  • Instagram

@2022 - trungquandev.com. Since 2016 - All Right Reserved. Developed by Trung Quân Dev