Để video player HTML5 hoạt động đầy đủ (seek, pause, volume, duration), server phải hỗ trợ HTTP Range Requests (partial content - status 206). Node.js dùng fs.createReadStream để stream phần dữ liệu được yêu cầu.
Server Node.js - Express (Complete)
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
app.get('/video', (req, res) => {
const videoPath = path.join(__dirname, 'videos', 'sample.mp4');
const stat = fs.statSync(videoPath);
const fileSize = stat.size;
const range = req.headers.range;
if (!range) {
// Không có header Range -> gửi toàn bộ (hoặc redirect)
res.writeHead(200, {
'Content-Length': fileSize,
'Content-Type': 'video/mp4'
});
fs.createReadStream(videoPath).pipe(res);
return;
}
// Parse Range header: "bytes=start-end"
const parts = range.replace(/bytes=/, '').split('-');
const start = parseInt(parts[0], 10);
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
const chunkSize = (end - start) + 1;
const head = {
'Content-Range': `bytes ${start}-${end}/${fileSize}`,
'Accept-Ranges': 'bytes',
'Content-Length': chunkSize,
'Content-Type': 'video/mp4'
};
res.writeHead(206, head); // 206 Partial Content
const stream = fs.createReadStream(videoPath, { start, end });
stream.pipe(res);
});
app.listen(3000, () => console.log('Server chạy cổng 3000'));
Client HTML5
<video width="640" height="360" controls> <source src="/video" type="video/mp4"> </video>
Giải thích Range Request
- Browser gửi request kèm header
Range: bytes=0-(lúc đầu) hoặcRange: bytes=1000000-(khi seek). - Server parse start/end, đọc file từ vị trí đó.
- Server trả về 206 Partial Content kèm header
Content-Range,Content-Lengthcủa chunk. - Browser cập nhật duration, cho phép seek mượt mà.
Nâng cao: Middleware reusable
function videoStreamMiddleware(videoDir) {
return (req, res, next) => {
const videoPath = path.join(videoDir, req.params.filename);
// ... logic range request như trên ...
};
}
app.get('/video/:filename', videoStreamMiddleware('./videos'));
Thư viện sẵn có (Khuyên dùng production)
- express-range - Middleware range request đơn giản.
- h5p-video-stream - Hỗ trợ đầy đủ.
- node-media-server - RTMP/HTTP-FLV/HLS/DASH server.
Lưu ý quan trọng
- Video phải được encode với moov atom ở đầu (faststart) để stream được. Dùng ffmpeg:
ffmpeg -i input.mp4 -movflags faststart output.mp4. - Hỗ trợ
Accept-Ranges: bytesheader cho browser biết server hỗ trợ range. - CORS header nếu client khác domain:
Access-Control-Allow-Origin: *. - Cache-Control:
public, max-age=31536000, immutablecho video tĩnh.