Upload files trong Nodejs
Trong bài viết này chúng ta sẽ cùng nhau xây dựng một trang web upload file sử dụng NodeJS, bài này mình sẽ cố gắng đi từng bước và giải thích kĩ từng đoạn code làm sao cho dễ hiểu nhất. Mình sẽ sử dụng kết hợp giữa các module như formidable đùng để parse form, module http giúp khởi tạo HTTP Web Server, module fs để xử lý file.
1. Module formidable
Có rất nhiều module hữu ích cho việc upload một file sử dụng Nodejs, mình sẽ sử dụng module formidable. Để cài đặt module này bạn cần mở terminal và gõ dòng lệnh:
npm i --save formidable
Sau khi cài đặt module xong bạn cần phải include nó vào chương trình:
const formidable = require('formidable')
Mình chọn module formidable bởi nó là một module khá phổ biến mà có một vài điểm nổi bật như:
Bài viết này được đăng tại [free tuts .net]
- Tốc độ khá nhanh (khoảng từ 900-2500MB/s) và parse dữ liệu ra nhiều luồng (sử dụng streams trong nodejs)
- Tự động ghi file vào ổ đĩa ( tại thời điểm mà mình viết bài này thì nó chưa hỗ trợ, bạn cần cùng kết hợp module fs để ghi file)
- Plugin API cho phép người dùng chỉnh cách thức parse và các plugin hỗ trợ.
- Chiếm ít bộ nhớ
- Dễ dàng bắt lỗi
- Nhiều phương thức cho việc test
2. Xây dựng trang upload file sử dụng Nodejs
Mình sẽ chia cấu trúc thư mục của dự án thành 3 phần như sau:
- viewUploadForm.html : đây là file dùng để chứa giao diện trang web
- index.js: file chứa các đoạn code xử lý của server
- /uploads : thư mục chứa các file
Xây dựng giao diện trang upload
Mình sẽ dùng framework Bootstrap 4 để xây dựng trang giao diện một cách nhanh hơn. File viewUploadForm.html
dẽ có nội dung như sau:
<!DOCTYPE html> <html lang="vi"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Upload file using NodeJS</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"> </head> <body> <div class="container"> <div class="row" > <div class="col-md-12"> <div class="card" style="margin-top: 5%; padding: 5%;"> <h3 style="text-align: center;">Upload file using nodejs - Freetuts.net</h3><hr> <form action="/upload" method="POST" enctype="multipart/form-data"> <div class="form-group"> <input type="file" name="files" class="form-control-file border"> </div> <button class="btn btn-primary btn-block">Upload File</button> </form> </div> </div> </div> </div> </body> </html>
Ở đây mình sẽ tạo một form upload có action="/upload" mà method là POST, attribute enctype="multipart/form-data" chỉ định form sẽ đươc encode.
Xây dựng HTTP Web Server
Bạn cần xây dựng HTTP Web Server để xử lý các yêu cầu từ người dùng, cụ thể trong dự án này là upload file. Để khởi tạo bạn cần phải sử dụng module HTTP có trong Nodejs. Nếu bạn không biết cách khởi tạo HTTP Web Server bạn hãy đọc bài viết cách khởi tạo HTTP Web Server trong NodeJS mà mình đã viết trong seri này trước đó.
Trong file index.js
ta tiến hành dùng hàm http.createServer() để khởi tạo server:
const http = require('http'); const formidable = require('formidable'); const fs = require('fs'); //Sử dujgn module fs để đọc nội dung file viewUploadForm const viewFormUpload = fs.readFileSync('./viewUploadForm.html') //Khởi tạo server http.createServer(function (req, res) { //Bắt yêu cầu resquest gửi đến url /upload có method là POST if (req.url == '/upload' && req.method == 'POST') { } else { //Hiển thị ra form upload file res.writeHead(200, {'Content-Type': 'text/html'}); return res.end(viewFormUpload); } }).listen(6969); //Sử dụng port 6969
Server sẽ lắng nghe ở port 6969, và trả về form upload. Vì giao diện của trang web nằm trong file viewFormUpload.html
nên để lấy nội dung file đó mình phải dùng module fs của NodeJS để đọc.
Xử lý yêu cầu upload file từ người dùng
Khi upload file người dùng sẽ được gửi một request mới method là POST, việc cần làm bây giờ dùng module formdable để parse form. Trong phần kiểm tra điều kiện người dùng đã upload file đến server bạn sẽ xử lý upload file như sau:
//Khởi tạo API formidable const form = new formidable.IncomingForm(); //Tiến hành parse form form.parse(req, function (err, fields, files) { //Lấy đượng dẫn tạm thời của file khi upload let oldPath = files.files.path //Đường dẫn mới khi upload let newPath = __dirname + '/uploads/' + files.files.name //Tiến hành rename file tạm thời thành đường dẫn file mới fs.rename(oldPath, newPath, (err) => { //Trả ra lõi nếu gặp if (err) return res.end(err) //Trả về kết quả thành công return res.end('<h1 style="color: green;">Upload success !</h1>') }) })
Trước tiên bạn phải khởi tạo API IncomingForm() để formidable biết rằng có form submit, sau đó dùng hàm form.parse() để parse request của clients gửi về lúc này hàm sẽ trả về một callback chứa các giá trị khi form đã được parse. Việc bạn cần làm bây giờ là rename file bằng module fs.
Module formidable còn cho phép bạn thêm một số options, bạn có thể truyền 1 objects chứ các tinh chỉnh vào hàm:
const options = { //Options object } const form = new formidable.IncomingForm(options);
Chúng ta có thể tinh chỉnh một vài giá trị như :
- options.encoding {string} - Mặc định 'utf-8', tinh chỉnh kiểu encode ở các trường ở form.
- options.uploadDir {string} - Đường dẫn mặc định khi upload file, bạn có thể chỉnh sửa sau đó sử dụng fs.rename(). Mặc định sẽ là os.tmpdir()
- options.keepExtensions {boolean} - mặc định là false, có giữ phần
- options.maxFileSize {number} - mặc định 200 * 1024KB = 200MB, giới file tối đa uploads
- options.maxFields {number} - mặc 1000; giới hạn các trường để parse, đặt 0 đẻ không giới hạn.
- options.maxFieldsSize {number} - default 20 * 1024 * 1024 (20mb);giới hạn bộ nhớ được dùng để parse các trường (trừ trường files)
- options.hash {boolean} - mặc định false; kiểm tra tổng thể được tính cho các tệp đến, đặt thuật toán này thành một số thuật toán băm, xem crypto.createHash để biết các thuật toán có sẵn
- options.multiples {boolean} - mặc định false; khi bạn gọi phương thức .parse, đối số tệp (của callback) sẽ chứa các mảng tệp cho các đầu vào gửi nhiều tệp bằng cách sử dụng nhiều thuộc tính HTML5. Ngoài ra, đối số trường sẽ chứa các mảng giá trị cho các trường có tên kết thúc bằng '[]'.
Cuối cùng file index.js
khi hoàn thiện sẽ như sau:
const http = require('http'); const formidable = require('formidable'); const fs = require('fs'); //Sử dụng module fs để đọc nội dung file viewUploadForm const viewFormUpload = fs.readFileSync('./viewUploadForm.html') //Khởi tạo server http.createServer(function (req, res) { //Bắt yêu cầu resquest gửi đến url /upload có method là POST if (req.url == '/upload' && req.method == 'POST') { //Khởi tạo đối tượng formidable const option = { } const form = new formidable.IncomingForm(); //Tiến hành parse form form.parse(req, function (err, fields, files) { //Lấy đượng dẫn tạm thời của file khi upload let oldPath = files.files.path //Đường dẫn mới khi upload let newPath = __dirname + '/uploads/' + files.files.name //Tiến hành rename file tạm thời thành đường dẫn file mới fs.rename(oldPath, newPath, (err) => { //Trả ra lõi nếu gặp if (err) return res.end(err) //Trả về kết quả thành công return res.end('<h1 style="color: green;">Upload success !</h1>') }) }) } else { //Hiển thị ra form upload file res.writeHead(200, {'Content-Type': 'text/html'}); return res.end(viewFormUpload); } }).listen(6969); //Sử dụng port 6969
Trên đây là những kiến thức cơ bản về xử lý upload file trong Nodejs, thường thì khi xử lý upload file người ta dùng module Multer để hỗ trợ upload và module Express để khởi tạo server. Vì đây là bài viết nằm tronng phần NodeJS cơ bản nên mình sẽ đề cập đến việc upload file bằng cách kết hợp giữa 2 module Multer và Express trong phần về Express framework. Mong bài viết này có thể giúp ích cho bạn cho việc lập trình với Nodejs, cảm ơn bạn đã quan tâm bài viết này.