8 javascript header http node.js
前段时间我在一些流媒体视频教程中找到了这个功能,这样就不需要将整个文件加载到RAM中来提供文件(这样你就可以提供大视频文件而不会因为超出内存容量而崩溃Node.js - 用电影长度的视频文件不难超越,增加内存分配只是一个创可贴解决方案).
var fs = require("fs"),
http = require("http"),
url = require("url"),
path = require("path");
var dirPath = process.cwd();
var videoReqHandler = function(req, res, pathname) {
var file = dirPath + "/client" + pathname;
var range = req.headers.range;
var positions = range.replace(/bytes=/, "").split("-");
var start = parseInt(positions[0], 10);
fs.stat(file, function(err, stats) {
if (err) {
throw err;
} else {
var total = stats.size;
var end = positions[1] ? parseInt(positions[1], 10) : total - 1;
var chunksize = (end - start) + 1;
res.writeHead(206, {
"Content-Range" : "bytes " + start + "-" + end + "/" + total,
"Accept-Ranges" : "bytes",
"Content-Length" : chunksize,
"Content-Type" : "video/mp4"
});
var stream = fs.createReadStream(file, {
start : start,
end : end
}).on("open", function() {
stream.pipe(res);
}).on("error", function(err) {
res.end(err);
});
}
});
};
module.exports.handle = videoReqHandler;
Run Code Online (Sandbox Code Playgroud)
它在Chrome和FF中运行良好,但是,当Internet Explorer或Edge(如果你愿意)(新名称,同样可怜的功能支持)请求mp4时,它会崩溃服务器.
var positions = range.replace(/bytes=/, "").split("-");
^
TypeError: Cannot read property 'replace' of undefined
Run Code Online (Sandbox Code Playgroud)
我怀疑这是因为范围标题不是强制性的,而且这个函数需要它们.
我的问题是,如何修改此函数以避免在range未发送标头时崩溃?我对标题或视频流不太了解,而且我对理解以块状态读取文件非常不错,所以我真的可以在这个涉及所有三个的函数上使用一些帮助.
到目前为止,根据答案@AndréDion链接:
弄清楚了.IE11确实支持伪流,但是它需要"Accept-Ranges:bytes"标头才会打扰请求范围,因此无论是否实际发送字节范围,服务器都需要响应.我不得不修改我的vid-streamer模块来做到这一点.
我尝试将处理程序代码包装在:
if (req.headers.range) {
console.log('Video request sent WITH range header!');
// ... handler code ...
} else {
console.log('Video request sent without range header!');
res.writeHead(206, {
"Accept-Ranges": "bytes"
});
res.end();
}
Run Code Online (Sandbox Code Playgroud)
但似乎没有发生任何事情 - 服务器停止崩溃,并继续在其他浏览器上工作,但IE似乎没有加载视频.我期待IE等待响应,然后发送另一个请求,这次包括一个范围标题,但似乎没有发生.
在向IE发送接受范围标头时,我可能需要发送不同于206的响应代码吗?我不知道它会是什么,但是当我用accept-rages标头回复时,IE似乎重复了两次请求(但不包括范围标题,这就是我需要的).
就像现在一样,如果我使用条件运行服务器,如上所示,然后尝试在IE中加载一次视频,然后尝试在Chrome中加载它,我得到这些日志:
Video request sent without range header!
Video request sent without range header!
Video request sent without range header!
Video request sent WITH range header!
Run Code Online (Sandbox Code Playgroud)
IE发送三个没有范围标题的请求,Chrome当然总是按预期发送范围标题,发送一个请求并成功加载视频.我只是不确定从哪里开始.
看起来 Internet Explorer 需要的不仅仅是 Accept-Ranges 标头。此 MSDN 论坛帖子表明您还需要使用返回ETag的If-Range 标头进行响应。像这样的东西:
console.log('Video request sent without range header!');
res.writeHead(206, {
"Accept-Ranges": "bytes",
"If-Range": "\"<ETag#>\""
});
Run Code Online (Sandbox Code Playgroud)
不幸的是,从那以后我现在无法进行任何测试,所以让我知道进展如何,当我有机会时,我会进一步调查并编辑我的帖子。
我进行了进一步的调查,发现 If-Range 是不必要的。事实上,这个请求处理程序对于 Internet Explorer 来说似乎不够强大。这是我的有效代码:
var videoReqHandler = function(req, res, pathname) {
var file = path.resolve(__dirname, pathname);
fs.stat(file, function(err, stats) {
if (err) {
if (err.code === 'ENOENT'){
//404 Error if file not found
res.writeHead(404, {
"Accept-Ranges" : "bytes",
"Content-Range" : "bytes " + start + "-" + end + "/" + total,
"Content-Length" : chunksize,
"Content-Type" : "video/mp4"
});
}
res.end(err);
}
var start;
var end;
var chunksize;
var total = stats.size;
var range = req.headers.range;
if (range) {
var positions = range.replace(/bytes=/, "").split("-");
end = positions[1] ? parseInt(positions[1], 10) : total - 1;
start = parseInt(positions[0], 10);
}else{
start = 0;
end = total - 1;
}
if (start > end || start < 0 || end > total - 1){
//error 416 is "Range Not Satisfiable"
res.writeHead(416, {
"Accept-Ranges" : "bytes",
"Content-Range" : "*/" + stats.size,
"Content-Type" : "video/mp4"
});
res.end();
return;
}
if (start == 0 && end == total -1){
res.writeHead(200, {
"Accept-Ranges" : "bytes",
"Content-Range" : "bytes " + start + "-" + end + "/" + total,
"Content-Length" : total,
"Content-Type" : "video/mp4"
});
}else{
res.writeHead(206, {
"Accept-Ranges" : "bytes",
"Content-Range" : "bytes " + start + "-" + end + "/" + total,
"Content-Length" : end - start + 1,
"Content-Type" : "video/mp4"
});
}
var stream = fs.createReadStream(file, {
start : start,
end : end
}).on("open", function() {
stream.pipe(res);
}).on("error", function(err) {
res.end(err);
});
});
};
Run Code Online (Sandbox Code Playgroud)
这会添加一些缺少的错误检查,例如确保请求的范围是有效范围,并且如果请求没有范围标头,则返回带有代码 200 的整个文件。不过,为了使其对于生产服务器来说坚如磐石,还应该做一些事情:
最后一点:这段代码可以在 IE 和 Edge 中正常工作,但我确实注意到,由于某种原因,它们最终两次请求完整文件!我的设置中的请求如下:
最后一点,在我添加响应完整文件和 200 状态的能力之前,当没有范围标头时,IE 将显示视频的黑框,上面印有“解码错误”。如果有人能让我知道原因,那就太棒了!
| 归档时间: |
|
| 查看次数: |
967 次 |
| 最近记录: |