Lâu rồi mình chưa viết bài trên blog hôm nay sẽ chia sẽ với anh chi chủ đề Cách làm “upload chunks large video file to nodejs nginx”
Lỗi 413 trong Nginx là “Request Entity Too Large” (Yêu cầu quá lớn). Nó xuất hiện khi Nginx nhận được một yêu cầu HTTP POST hoặc PUT mà kích thước nội dung vượt quá giới hạn mà Nginx được cấu hình để xử lý.
Nguyên nhân phổ biến của lỗi 413 là do giới hạn kích thước của yêu cầu mà Nginx cho phép. Khi Nginx nhận được một yêu cầu POST hoặc PUT, nó cần phải biết trước kích thước của nội dung để xử lý yêu cầu này một cách hiệu quả. Mặc định, Nginx có giới hạn kích thước nội dung cho mỗi yêu cầu, và nếu kích thước nội dung vượt quá giới hạn này, Nginx sẽ trả về lỗi 413.
Ý tưởng chúng ta sẽ chia nhỏ nhiều phần ở client sau đó upload từng phần nhỏ lên server, sau đó nối lại. Sau đây tôi xin chia sẽ code để xử lý vấn đề này
Vị trí file này thường là /etc/nginx/nginx.conf
1 2 3 4 |
http { client_max_body_size 20M; ... } |
refresh lại cấu hình nginx bằng lênh
1 |
service nginx restart |
Code này là một function trong vuejs 2 nha anh chị, anh chị có thể tham khảo tùy biến qua code của anh chị
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
async triggerUploadChunks(){ if(this.name.length ===0){ alert("Vui lòng nhập tên video!") this.$refs.videoName.focus() return false } if(this.videoFile == null){ alert("Chưa chọn video để tải lên!") this.$refs.videoFile.focus() return false } this.triggerUploadText = '<i class="fa fa-spinner fa-spin"></i> Tải lên' //const chunkSize = 1024 * 1024; // 1MB chunks (you can adjust the size) const chunkSize = 1*1024 * 1024 // 1MB chunks (you can adjust the size) let offset = 0 console.log('this.videoFile.size',this.videoFile.size) while (offset < this.videoFile.size) { let chunk = this.videoFile chunk = chunk.slice(offset, offset + chunkSize) // Sử dụng Axios để tải lên từng phần const formData = new FormData() formData.append('fileChunk', chunk) formData.append('username', this.currentUser.username) await axios.post(apiUrl+ '/video/upload-video-chunks', formData, { headers: { 'Content-Type': 'multipart/form-data', 'username': this.currentUser.username }, withCredentials: true, // Cho phép gửi cookie và thông tin xác thực trong yêu cầu onUploadProgress: progressEvent => { this.progressUploadFinished = offset/this.videoFile.size console.log(offset/this.videoFile.size); } }).then(res => { console.log(res.data) this.pathForConvert = res.data.path this.videoId = res.data.filename }) .catch(error => { console.log(error); }); console.log(`offset: ${offset}, chunkSize: {chunkSize}`) offset += chunkSize } if(offset >= this.videoFile.size){ this.modalUploadVideo = false this.triggerUploadText = '<i class="fa fa-cloud-upload" aria-hidden="true"></i> Tải lên' alert("Đã tải lên thành công, quá trình xử lý video sẽ tốn thời gian tùy vào dung lượng video") this.getList() const payload ={ username: this.currentUser.username, name: this.name, pathForConvert: this.removeLastSegmentFromPath(this.pathForConvert), id: this.videoId } this.progressUploadFinished = 1 console.log('payload',payload) // Sau khi đã tải lên tất cả các phần, hãy thông báo cho máy chủ để thực hiện việc nối tệp. await axios.post(apiUrl+ '/video/upload-video-chunks-join-and-convert', payload, { headers: { 'Content-Type': 'application/json' } }) .then(response => { }) .catch(error => { // Xử lý error nếu cần }); } } |
sẽ có 2 route để làm việ này: route thứ nhất là apiUrl+ ‘/video/upload-video-chunks’ mình để nhận xử lý upload từng phần và route thứ 2 upload-video-chunks-join-and-convert chúng ta sẽ nối file. Sau đây là code để anh chị tham khảo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
const videoController = require("../controllers/videoControllers"); const authMiddleware = require('../controllers/authMiddleware'); const path = require('path'); const fs = require("fs"); const multer = require('multer'); const dotenv = require("dotenv"); dotenv.config(); // Đặt thư mục lưu trữ video tải lên const storage = multer.diskStorage({ destination: function (req, file, cb) { // Tạo thư mục đích nếu chưa tồn tại //console.log('req',req.header('username')); const username = req.header('username'); if (!fs.existsSync(process.env.FOLDER_UPLOAD + "/" + username + "/temp")) { fs.mkdirSync(process.env.FOLDER_UPLOAD + "/" + username + "/temp", { recursive: true }); } cb(null, process.env.FOLDER_UPLOAD + "/" + username + "/temp"); }, filename: function (req, file, cb) { cb(null, Date.now() + path.extname(file.originalname)); } }); const upload = multer({ storage: storage, limits: { fileSize: 100000000000 }, // Giới hạn kích thước tệp lên là 100000000 bytes (100MB). }); const router = require("express").Router(); router.post("/upload-video-chunks", upload.single('fileChunk'), videoController.uploadVideoChunks); router.post("/upload-video-chunks-join-and-convert", videoController.uploadVideoChunksJoinAndConvert); module.exports = router; |
Khi upload ok chúng ta sẽ trả về path và các thông tin liên quan đến folder chứa các từng phần của file lớn
1 2 3 4 5 6 7 |
uploadVideoChunks: async(req,res) => { try{ res.status(200).json(req.file); }catch(err){ res.status(200).json(err); } } |
Đây là function thực hiện chức năng nối file lại và trong trường hợp của tôi là file mp4 sau đó convert sang file .m3u8
Code để anh chị tham khảo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
uploadVideoChunksJoinAndConvert: async(req,res) => { try{ const date = Math.floor(new Date().getTime() / 1000); let videos = fs.readFileSync('./databases/videos.json', 'utf8'); videos = JSON.parse(videos); const newVideo = { id: req.body.id, type: 'processing', username: req.body.username, name: req.body.name, path: '', date: date, thumbnail: '', }; videos.push(newVideo); await videoControllers.writeFile('./databases/videos.json', JSON.stringify(videos)); const outputFile = req.body.pathForConvert + "/joined.mp4"; await videoControllers.mergeVideosInFolder(req.body.pathForConvert, outputFile,req.body.id,req.body.username); res.status(200).json({ message: 'Tải lên video thành công và convert sang .m3u8 thành công!', type: 1 }); }catch(err){ res.status(200).json(err); } } |
Ok mình đã trình bày bài viết xong
Một số từ khóa tìm kiếm bài viết này trên google:
-upload chunks large video file to nodejs nginx
-upload chunks
-upload file mp4 lên node js và nginx
Mọi sự sao chép xin ghi rõ nguồn là fcwordpress.net
Chuyên trang về wordpress: hướng dẫn thiết kế theme, plugin, thủ thuật wordpress