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

 

运行结果

 

posted @ 2019-08-29 16:56  KIU的博客  阅读(663)  评论(0编辑  收藏  举报