是否是被圖片騙進來了?哈哈不要着急走,其實也不是跟圖不要緊,咱們此次就是說斷點續傳的那些事。
咱們寫代碼的有時候工做中會作一些上傳/下載圖片或者文件的操做。萬一線路中斷,不具有斷點續傳的 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
是否是躍躍欲試??
若是對你有幫助請點個贊噻!