本文基于http Range Requests协议,实现了片段下载功能。
使用场景包括基于浏览器的流文件片段传输、基于客户端的片段下载等。
原则
Http可以通过与Range Requests相关的头与服务器协商,实现部分请求。
具体协议在这里就不细说了。详情可以参考这两篇文章:
https://tools.ietf.org/html/rfc7233https://www.jb51.net/article/68284.htm在下面公布了实施过程。
服务器代码
服务器由节点实现:
app . use(async CTX={ const file=PATH . join(_ dirname,` $ { PATH } $ { CTX . PATH } `));//1,404检查尝试{fs.accessSync(文件);} catch(e){ return CTX . response . status=404;} const method=CTX . request . method;const { size }=fs.statSync(文件);//2.响应head请求并返回文件大小if(' head '==method){ return CTX . set(' content-length ',size);} const range=CTX . headers[' range '];//3.通知浏览器,如果(!idspnonenote)出现问题,它可以发出部分请求。range){ return CTX . set(' Accept-Ranges ',' bytes ');} const { start,end }=getRange(范围);//4.如果(开始=大小| |结束=大小){CTX,请检查请求范围。回应。状态=416;返回ctx.set('Content-Range ',` bytes */$ { size } `);} //5,206部分响应CTX . response . status=206;ctx.set('接受范围','字节');ctx.set('Content-Range ',` bytes ${start}-${end?end : size-1 }/$ { size } `);ctx.body=fs.createReadStream(文件,{ start,end });});app.listen(3000,()=console.log('部分内容服务器启动'));函数GetRange(range){ var match=/bytes=([0-9]*)-([0-9]*)/。exec(范围);const RequestRange={ };if(match){ if(match[1])request range . start=Number(match[1]);if(match[2])request range . end=Number(match[2]);}返回requestRange}代码实现的功能逻辑大致为:
检查请求的资源,如果它不存在,则响应404。对于HEAD请求,返回资源大小。如果GET请求没有告诉范围,返回Content-Length,并告诉浏览器它可以发出分片请求。如果请求设置范围,检查范围是否合法,如果非法,返回合法范围。一切正常,获取文件的范围部分。做流量响应代码非常简单。实现一次范围请求协议是可以的。当然,协议的内容在这里没有完全实现,但是已经满足了这里演示的要求。
服务器代码是可以的,用浏览器演示检查一下。
浏览器示例
现代浏览器基本上实现范围请求。这里,音频标签被用作示例。
Html head title分片streaming/title script type=' text/JavaScript ' function jump(){ const player=document . getelementbyid(' music player ');//从30秒开始播放播放器。currenttime=30}/script/head body audio id=' music player ' src=' http : http 3360127 . 0 . 0 . 1:3000/source . MP3 ' controls/audio button onclick=' jump()'剪切到30s/button /body/html,最终效果如下:
比较这两个数字,当html加载完成时,浏览器会自动请求资源。此时,标头的Range:字节=0-,表示从第0个字节开始加载资源。当您单击跳到30s时,标题变为Range:字节=3145728-。
使用这个服务器代码,您还可以实现一个客户端来模拟分包下载。
节点分包下载
这个例子演示了一个资源可以部分地同时下载,然后合并到一个文件中。
这里也是用节点实现的:
从“请求”导入请求;从"路径"导入路径;从" fs "导入fs;const SINGLE=1024 * 1000 const SOURce=' http://127。0 .0 .1:3000/SOURce。MP3 ';请求({ method: 'HEAD ',uri: SOURCE,},(err,res)={ if (err)返回控制台。err(err);const文件=路径。join(_ dirname,' ./下载/来源。MP3’);请尝试{ fs.closeSync(fs.openSync(文件,' w ');} catch(err){返回控制台。错误(err);} const size=Number(RES . header[' content-length ']);常量长度=ParSeint(大小/信号);用于(设I=0;ileng tti){ 0让start=i * SINGLE让end=i==长度?(I 1)* SINGLE-1 : size-1;请求({ method: 'GET ',uri: SOURCE,标头RS : { ' range ' : ' bytes=$ { start }-$ { end } `},}).on('response ',(resp)={ const range=resp。标题['内容范围'];const match=/bytes([0-9]*)-([0-9]*)/.exec(范围);start=match[1];end=match[2];}).管道(fs.createWriteStream(文件,{start,end });}});代码比较简单,就是开启多个超文本传送协议(超文本传输协议的缩写)请求,并发的下载资源,然后根据响应的内容范围,写到文件的对应位置。
参考文章:
https://工具。IETF。org/html/RFC 7233https://www .JB 51。net/article/68284。html文件的后缀
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。