当用户在听一首歌的时候,如果听到一半(网络下载了一半),网络断掉了,用户需要继续听的时候,文件服务器不支持断点的话,则用户需要重新下载这个文件。而Range支持的话,客户端应该记录了之前已经读取的文件范围,网络恢复之后,则向服务器发送读取剩余Range的请求,服务端只需要发送客户端请求的那部分内容,而不用整个文件发送回客户端,以此节省网络带宽。
为了实现中断恢复下载的需求,需要能下载指定下载的实体范围
Content-Type
中标明multipart/byteranges
curl -v --header "Range: bytes=2-100" http://www.zhufengpeixun.cn/skin/20142/img/logo.png
如果Server支持Range,首先就要告诉客户端,支持Range,之后客户端才可能发起带Range的请求。这里套用唐僧的一句话,你不说我怎么知道呢。response.setHeader('Accept-Ranges', 'bytes');
Server通过请求头中的Range: bytes=0-xxx
来判断是否是做Range请求,如果这个值存在而且有效,则只发回请求的那部分文件内容,响应的状态码变成206,表示Partial Content,并设置Content-Range。如果无效,则返回416状态码,表明Request Range Not
// server
let http = require('http');
let url = require('url')
let path = require('path');
let fs = require('fs');
http.createServer(function(req,res){
let p = path.join(__dirname,'./1.bytes.txt');
let start = 0;
fs.stat(p,function(err,stat){
let start = 0
let end = stat.size - 1; // 文件的大小
let range = req.headers['range'];
if(range){
res.setHeader('Accept-Range','bytes');
res.statusCode = 206;
let result = range.match(/bytes=(\d*)-(\d*)/);
if(result){
start = result[1]? parseInt(result[1]):start;
end =result[2]? parseInt(result[2])-1:end
}
}
return fs.createReadStream(p,{start,end}).pipe(res);
})
}).listen(8080);
// client
let options = {
hostname:'localhost',
port:8080,
path:'/',
method:'GET'
}
let fs = require('fs');
let path = require('path');
let http = require('http');
let ws = fs.createWriteStream('./download.txt');
let start = 0;
let pause = false
process.stdin.on('data',function(chunk){
chunk = chunk.toString();
if(chunk.startsWith('p')){
pause = true;
}else{
pause = false;
downLoad();
}
})
function downLoad(){
options.headers = {
Range: `bytes=${start}-${start+10}`
}
start+=10;
http.request(options,function(response){
let buffers = []
response.on('data',function(data){
buffers.push(data);
});
response.on('end',function(){
let b = Buffer.concat(buffers);
ws.write(b);
if(start<100&&pause === false){
setTimeout(function(){
downLoad()
},1000)
}
})
})
}
downLoad();