我正在使用
expressjs框架,并且已经做到了:
// Readable Streams Storage Classclass FileReadStreams { constructor() { this._streams = {}; } make(file, options = null) { return options ? fs.createReadStream(file, options) : fs.createReadStream(file); } get(file) { return this._streams[file] || this.set(file); } set(file) { return this._streams[file] = this.make(file); }}const readStreams = new FileReadStreams();// Getting file stats and caching it to avoid disk i/ofunction getFileStat(file, callback) { let cacheKey = ['File', 'stat', file].join(':'); cache.get(cacheKey, function(err, stat) { if(stat) { return callback(null, stat); } fs.stat(file, function(err, stat) { if(err) { return callback(err); } cache.set(cacheKey, stat); callback(null, stat); }); });}// Streaming whole filefunction streamFile(file, req, res) { getFileStat(file, function(err, stat) { if(err) { console.error(err); return res.status(404); } let bufferSize = 1024 * 1024; res.writeHead(200, { 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': 0, 'Content-Type': 'audio/mpeg', 'Content-Length': stat.size }); readStreams.make(file, {bufferSize}).pipe(res); });}// Streaming chunkfunction streamFileChunked(file, req, res) { getFileStat(file, function(err, stat) { if(err) { console.error(err); return res.status(404); } let chunkSize = 1024 * 1024; if(stat.size > chunkSize * 2) { chunkSize = Math.ceil(stat.size * 0.25); } let range = (req.headers.range) ? req.headers.range.replace(/bytes=/, "").split("-") : []; range[0] = range[0] ? parseInt(range[0], 10) : 0; range[1] = range[1] ? parseInt(range[1], 10) : range[0] + chunkSize; if(range[1] > stat.size - 1) { range[1] = stat.size - 1; } range = {start: range[0], end: range[1]}; let stream = readStreams.make(file, range); res.writeHead(206, { 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': 0, 'Content-Type': 'audio/mpeg', 'Accept-Ranges': 'bytes', 'Content-Range': 'bytes ' + range.start + '-' + range.end + '/' + stat.size, 'Content-Length': range.end - range.start + 1, }); stream.pipe(res); });}router.get('/:file/stream', (req, res) => { const file = path.join('path/to/mp3/', req.params.file+'.mp3'); if(/firefox/i.test(req.headers['user-agent'])) { return streamFile(file, req, res); } streamFileChunked(file, req, res);});网站的完整资源在这里
尝试修复您的代码:
这将强制浏览器对资源进行分块处理。
var header = { 'Content-Length': range[1], 'Content-Type': type, 'Access-Control-Allow-Origin': req.headers.origin || "*", 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS', 'Access-Control-Allow-Headers': 'POST, GET, OPTIONS', 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': 0 }; if(/firefox/i.test(req.headers['user-agent'])) { res.writeHead(200, header); } else { header['Accept-Ranges'] = 'bytes'; header['Content-Range'] = 'bytes ' + range[0] + '-' + range[1] + '/' + total; header['Content-Length'] = range[2]; res.writeHead(206, header); }


