是否是被图片骗进来了?哈哈不要着急走,其实也不是跟图不要紧,咱们此次就是说断点续传的那些事。
咱们写代码的有时候工做中会作一些上传/下载图片或者文件的操做。万一线路中断,不具有断点续传的 HTTP/FTP 服务器或下载软件就只能从头重传,比较好的 HTTP/FTP 服务器或下载软件具备断点续传能力,容许用户从上传/下载断线的地方继续传送,这样大大减小了用户的烦恼。
复制代码
其实啊,为了实现中断恢复下载的需求,须要能下载指定下载的实体范围:node
curl -v --header "Range:bytes=0-10" http://pic26.nipic.com/20130117/10558908_124756651000_2.jpg
复制代码
运行一下获得的这个结果:promise
从http那段服务器返回给咱们的信息能够看出以下信息(206表明服务器答应咱们的range请求方式)缓存
首先客户端要发一个头Range:bytes=0-10,而后服务端返回一个头 // Accept-Ranges:bytes // Content-Range:0-10/总大小bash
// 获取范围请求
let http = require('http');
let fs = require('fs');
let path = require('path');
let { promisify } = require('util');//这个模块是包装某个东西成为promise的。
let stat = promisify(fs.stat);
let server = http.createServer(async function (req, res) {
let p = path.join(__dirname, 'con.txt');
// 判断当前文件的大小
let statObj = await stat(p);
let start = 0;
let end = statObj.size - 1; // 读流是包前又包后的:statObj.size 是文件的大小。
let total = end
let range = req.headers['range'];
if (range) {//判断客户端是否有带range的请求
// 告诉它支持范围请求
res.setHeader('Accept-Ranges','bytes');
// ['匹配的字符串','第一个分组']
let result = range.match(/bytes=(\d*)-(\d*)/);
start = result[1]?parseInt(result[1]):start;
end = result[2]?parseInt(result[2])-1:end;
// 获取成功而且文件总大小是多少
// Content-Range:0-10/总大小
res.setHeader('Content-Range',`${start}-${end}/${total}`)
}
res.setHeader('Content-Type', 'text/plain;charset=utf8');
fs.createReadStream(p, { start, end }).pipe(res);
});
server.listen(3000);
复制代码
这样一个简单的服务器端就写好了。服务器
//首先要写一个options
let options = {
hostname:'localhost',
port:3000,
path:'/',
method:'GET'
}
let fs = require('fs');
let path = require('path');
let http = require('http');
let ws = fs.createWriteStream('./download.txt');
let pause = false;
let start = 0;
// 下载,每次获取10个
process.stdin.on('data',function(chunk){
chunk = chunk.toString();
if(chunk.includes('p')){ //输入p就是暂停
pause = true
}else{
pause = false;
download();
}
});
function download(){
options.headers = {
Range:`bytes=${start}-${start+10}`
}
start+=10;
// 发请求
http.get(options,function(res){
let range = res.headers['content-range'];
let total = range.split('/')[1];
let buffers = [];//建立一个缓存区,把读到的数据都放在里面
//,等到end的时候就整个取出来。
res.on('data',function(chunk){
buffers.push(chunk);
});
res.on('end',function(){
//将获取的数据写入到文件中
ws.write(Buffer.concat(buffers));
setTimeout(function(){
if(pause === false&&start<total){
download();
}
},1000)
})
})
}
download();
复制代码
代码很是浅显易懂。 最后咱们在同级目录下建立一个con.txt文件。用node执行一下客户端文件,就会实现功能啦。网络
有时候即便终端发起续传请求是url对应问问价在服务器端已经发生变化,那么很显然此时须要一个标识问价惟一的方式,curl
Etag(Entity Tags)主要为了解决 Last-Modified 没法解决的一些问题。async
为此,HTTP/1.1 引入了 Etag。Etag 仅仅是一个和文件相关的标记,能够是一个版本标记,例如:v1.0.0;或者说 “627-4d648041f6b80” 这么一串看起来很神秘的编码。可是 HTTP/1.1 标准并无规定 Etag 的内容是什么或者说要怎么实现,惟一规定的是 Etag 须要放在 “” 内,通常状况下Etag的值是时间+文件大小
。工具
If-Modified-Since,和 Last-Modified 同样都是用于记录页面最后修改时间的 HTTP 头信息,只是 Last-Modified 是由服务器往客户端发送的 HTTP 头,而 If-Modified-Since 则是由客户端往服务器发送的头,能够看到,再次请求本地存在的 cache 页面时,客户端会经过 If-Modified-Since 头将先前服务器端发过来的 Last-Modified 最后修改时间戳发送回去,这是为了让服务器端进行验证,经过这个时间戳判断客户端的页面是不是最新的,若是不是最新的,则返回新的内容,若是是最新的,则返回 304 告诉客户端其本地 cache 的页面是最新的,因而客户端就能够直接从本地加载页面了,这样在网络上传输的数据就会大大减小,同时也减轻了服务器的负担。 若是想了解具体怎么实现能够看看静态服务里面的缓存。post
是否是跃跃欲试??
若是对你有帮助请点个赞噻!