NodeJS4-6静态资源服务器实战_range范围请求
range范围请求:向服务器发起请求可以申明我想请求判断内容的范围,从多少个字节到多少个字节,一次要求把所有的内容拿回来,服务器在得到相应的请求之后,从拿到对应的文件,拿到对应的字节返回给客户端.要实现这一功能,请求的时候在RequestHeaders里面放一个range对象和我们定义的范围,都好分割请求多个范围,
- range:bytes = [ start ] - [ end ]
在RequestHeaders里面放一个range对象和我们定义的范围,逗号分割请求多个范围,
- Accept-Ranges:bytes
是在响应中加一个响应头,这里表示服务器可以处理的格式字节
- Content-Range:bytes start-end/total
需要在ResponseHeaders中返回Content-Range表示返回给你的十字街,从哪里开始那里结束
添加一个文件处理range请求,添加range.js
/*参数 totalSize 需要整个的字节数 , req 读到客户端请求range的方位 resp */ module.exports = (totalSize,req,res) =>{ const range = req.headers['range']; //如果拿不到range就返回200,告诉它处理不了 if(!range){ return { code:200 }; } const sizes = range.match(/bytes=(\d*)-(\d*)/) const end = sizes[2] || totalSize - 1; const start = sizes[1] || totalSize - end; //异常情况,返回200 if(start > end || start < 0 || end > totalSize){ return {code:200}; } //设置头部 res.setHeader('Accept-Range','bytes'); res.setHeader('Content-Range',`bytes ${start} - ${end} / ${total} `) res.setHeader('Content-Length',end - start) //可以处理的情况返回以下结果 return { code : 206, start:parseInt(start), end:parseInt(end) } }
在route.js引入range.js
const fs =require('fs') const path = require('path') const Handlebars = require('handlebars') const promisify = require('util').promisify; const stat = promisify(fs.stat) const readdir = promisify(fs.readdir); // //引用range范围 // const range = require('./range') const config = require('../config/defaultConfig') const tplPath = path.join(__dirname,'../template/dir.tpl') const source = fs.readFileSync(tplPath); const template = Handlebars.compile(source.toString()) //引入新加的mime,对contentType的判断 const mime = require('./mime') const compress = require('./compress') //引用range范围 const range = require('./range') module.exports=async function(req,res,filePath){ try{ const stats =await stat(filePath) if(stats.isFile()){ const contentType = mime(filePath) res.statusCode = 200 res.setHeader('content-Type',contentType) let rs; const {code,start,end} = range(stats.size, req, res) if(code === 200){ res.statusCode = 200 rs = fs.createReadStream(filePath) }else{ res.statusCode = 216 //测试随便定 rs = fs.createReadStream(filePath,{start,end}) } // let rs = fs.createReadStream(filePath) if(filePath.match(config.compress)){ rs = compress(rs,req,res) } rs.pipe(res); // fs.readFile(filePath,(err,data)=>{ // res.end(data) // }); }else if(stats.isDirectory()){ //所有异步调用必须用await const files =await readdir(filePath); res.statusCode = 200 res.setHeader('content-Type','text/html') const dir = path.relative(config.root,filePath) const data = { title:path.basename(filePath), // dir:config.root, dir:dir?`/${dir}`:'', files:files.map(file=>{ return { file, icon:mime(file) } }) } res.end(template(data)); } }catch(ex){ console.error(ex); res.statusCode = 404 res.setHeader('content-Type','text/plain') res.end(`${filePath} is not a directory or file\n ${ex.error}`) } }
主要改变是红框这部分
安装curl来查看,运行
curl -r 0-2 -i http://127.0.0.1:9527/LICENSE
运行结果