为何打开HTML文件或视频时Node.js进程意外终止?
问题修复方案
你的Node.js服务进程崩溃、视频无法播放,是因为代码里存在几个关键错误,以下是问题点和修复方法:
错误1:endsWith调用语法错误
case endsWith('.mp4'):这行代码里,endsWith是字符串的专属方法,必须通过q.pathname调用,否则会因找不到该变量直接抛出错误,导致进程终止。应修改为:case q.pathname.endsWith('.mp4'):
错误2:提前调用res.end()中断流传输
在视频处理分支中,你手动调用了res.end(),但fs.createReadStream().pipe(res)会在流传输结束时自动触发res.end(),提前调用会直接关闭响应,导致视频流还没完成传输就中断,同时触发错误让进程崩溃,必须删掉这行res.end()。
错误3:未处理文件读取的异常情况
fs.readFile读取HTML文件时没有错误处理逻辑,如果文件不存在,会抛出未捕获的错误导致进程终止,需要在回调中添加错误处理。- 调用
await fileInfo(filename)时,如果视频文件不存在或读取失败,会抛出未捕获的错误,需要用try/catch包裹处理。
错误4:重复创建promisify方法
每次请求都重新创建fileInfo变量完全没必要,应该把util.promisify(fs.stat)提到服务器创建代码的外部,避免重复初始化。
修复后的完整代码
var url = require('url'); var http = require('http'); var path = require('path'); var util = require('util'); var fs = require('fs'); // 提前完成promisify,避免重复创建 const fileInfo = util.promisify(fs.stat); http.createServer(async (req, res) => { var q = url.parse(req.url, true); switch(true) { case q.pathname === '/': fs.readFile('./Crazy_Network.html', function(err, html){ if (err) { // 处理HTML文件读取错误 res.writeHead(500, {"Content-Type": "text/plain"}); res.end('读取HTML文件失败: ' + err.message); return; } res.writeHead(200, {"Content-Type": "text/html"}); res.write(html); res.end(); }); break; case q.pathname.endsWith('.mp4'): let filename = '.' + q.pathname; try { let { size } = await fileInfo(filename); let fileExtension = path.extname(filename).replace('.', ''); let { range } = req.headers; if (range) { let [start, end] = range.replace(/bytes=/, '').split('-') start = parseInt(start, 10); end = Math.min(start + 5000, size - 1); res.writeHead(206, { 'Content-Range': `bytes ${start}-${end}/${size}`, 'Accept-Ranges': 'bytes', 'Content-Length': (end - start) + 1, 'Content-Type': `video/${fileExtension}`, }); fs.createReadStream(filename, { start, end }).pipe(res); } else { res.writeHead(200, { 'Content-Type': `video/${fileExtension}`, 'Content-Length': size, }); fs.createReadStream(filename).pipe(res); } } catch (err) { // 处理视频文件不存在或读取错误 res.writeHead(404, {"Content-Type": "text/plain"}); res.end('视频文件不存在或读取失败: ' + err.message); } break; default: res.end('Pathname used doesn\'t do anything except this.') break; } }).listen(8080, () => { console.log('Server listening on port 8080'); })
内容的提问来源于stack exchange,提问作者Nooofs1
相关产品推荐
相关产品推荐

