- server
- Train of thought
- About index location negotiation
- The sample
- Train of thought
- client
- test
server
Train of thought
Breakpoint continuation servers are primarily concerned with a request header — Range, well, received in Node
let range = req.headers['range'];
<<<
bytes = 0-999
Copy the code
Bytes = 0-999 is the Range value, so we can use the entire value to control the start and end read.
[info] The range requested by the client is only a verbal request, and does not have any real influence on how to return data to the client or server. Well, it could be 0 or it could be 1 or it could even be 10086 if the server wants.
Once we get the range, we can map the x-x in the range to the start/end in our createStream to control the output.
fs.createReadStream(p, { start, end }).pipe(res);
Copy the code
[DANGER] Note: The createStream API is indexed before and after a package.
One other thing to note is that we are returning two headers to the client
-
Accept-Ranges:bytes
Indicates whether the server supports scoped requests and what type of segmented requests
-
Content-Range:bytes start-end/total
:Tell him where and how many bytes of data we returned this time, so that the client knows where to request data from the next time, and whether it is time to end the request.
About index location negotiation
Between creating writable and readable streams that specify indexes before and after packets,
Range:bytes=start-end Range:bytes=start-end We then set rs start and end on the server side with fs.createreadstream () and subtract one from the Range retrieved from the request header.
>>> Range:bytes=1-9
...
let range = req.headers['range'];
let result = range.match(/bytes=(\d*)-(\d*)/);
let start = result[0];
letend = result[1]; . res.setHeader('Accept-Range'.'bytes');
res.setHeader('Content-Range',`bytes ${start}-${end}/${statObj.size}`) //1-9/total res.statusCode = 206; . fs.createReadStream(filepath,{ start:start-1,end:end-1 //0-8 }); . >>> Range:bytes=10-18 >>> ...Copy the code
The sample
let http = require('http');
let fs = require('fs');
let path = require('path');
let { promisify } = require('util');
let stat = promisify(fs.stat);
let server = http.createServer(async function (req, res) {
let p = path.join(__dirname, 'content.txt');
let statObj = await stat(p);
let total = statObj.size;
let start = 0;
let end = total;
let range = req.headers['range'];
if (range) {
res.setHeader('Accept-Ranges'.'bytes');
letresult = range.match(/bytes=(\d*)-(\d*)/); start = result[1]? parseInt(result[1]):start; end = result[2]? parseInt(result[2]):end; res.setHeader('Content-Range',`bytes ${start}-${end}/${total}`)
}
res.setHeader('Content-Type'.'text/plain; charset=utf8');
// res.write('Output start');
fs.createReadStream(p, { start, end }).pipe(res);
});
server.listen(8080);
Copy the code
client
Knowing how the server controls the output, the client is simply ~
Why don’t we just go to the code?
.let options = {
hostname:'localhost',
port:8080,
path:'/',
method:'GET'
}
let ws = fs.createWriteStream('./download.txt');
let pause = false;
let start = 0;
let speed = 10;
let end = start+speed;
download();
process.stdin.on('data'.function(chunk){
chunk = chunk.slice(0,chunk.length-2);
option = chunk.toString();
switch(option){
case 'p':
pause = true;
break;
case 'c':
pause = false;
download();
default:
if(/^s\s-[0-9]+$/.test(option)){ option = option.slice(3); speed = parseInt(option); }}}); //--- --- ---function download(){
options.headers = {
Range:`bytes=${start}-${end}} http.get(options,function(res){
let range = res.headers['content-range'];
let total = range.split('/') [1];let buffers = [];
let nextEnd;
res.on('data'.function(chunk){
buffers.push(chunk);
});
res.on('end'.function(){
ws.write(Buffer.concat(buffers));
setTimeout(function() {if(pause === false&&start<total){ start = end+1; nextEnd = end+speed; end = nextEnd+1<total? nextEnd:total; download(); }},1000)})})}Copy the code
The above implementation of a breakpoint to continue the demo support pause download,
The only slight note is that we control the download through the Range:Bytes=x-xx header.
test
curl -v -H 'Range:bytes=0-9'http://localhost:8080 // The data index requested by chestnut in this article is packet before packet after packetCopy the code
- P: Pause the download
- C: Keep downloading
- S-xx: Changes the download speed
End