继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Nodejs打造静态资源服务器与文件上传

花满楼的小前端a
关注TA
已关注
手记 42
粉丝 111
获赞 2213

我是一枚小前端,前段时间开始学习Express4,并试着开发了一个博客站点,就个人站点来说,服务器配置并不是太差,可问题却很是伤脑筋:访问响应特别慢!原谅我非计算机专业出身,初入前端,后台并不太懂!后来使用HTML5的离线缓存加了个manifest,缓存后快的像本地静态文件样!然而小站由于个人自恋,动态内容不少,而技术强度又没达到,发现HTML5的这一套在这并不适用!所以该想其他办法了,于是想到了公司的项目,静态资源有另一个服务器打理,也就是静态资源服务器,静态资源既有压缩也有缓存,加载可快了;百度了一下,没想到基于Nodejs的静态资源服务器讲解文档不少呢,于是决定弄个折腾下;

其实静态资源的加载就是一个GET请求,客户端通过资源路径请求服务器的资源,服务器读取资源,返回状态码,设置响应头,调取资源响应到客户端,大致就这样一个过程;

下面开始搭建了:我是直接在同一个服务器下,开启了一个新站点,在主站点里,由Nodejs的反向代理,将静态资源的请求分发到静态资源的站点;原谅我前端出身,目前钟情于Nodejs,暂时还学不来大名鼎鼎的Nginx和阿帕奇;

case 'cdn.famanoder.com': //静态资源站的host
    proxy.web(req, res, { target: 'http://localhost:4000' });//静态资源站在4000端口
 break;

npm模块不可少,还是先通过npm init生成一个package.json吧;安装文件上传模块:npm install --save formidable,还需要用到的模块有http,url,path,fs,zlib,依次require进来,另外需要备一个mimeType模块;准备工作差不多了,如果也大概知道接下来怎么做了,那么开始正式搭建咱的静态服务器吧,第一次弄,难免粗糙,可是原理基本就是这样,具备了思维,写代码应该不会太难了,Bug尽管想我飞来吧!

粗步的分为GET和POST请求吧;GET处理静态资源的请求,POST处理接下来的文件上传,其他暂不做处理了,静态资源服务器嘛;处理静态资源的请求大概是这个路子:拿到请求的pathname,添加静态资源主目录dist,类似Express里的app.use(express.static(path.join(__dirname, 'public')));首先由fs.exists判断请求资源是否存在,不存在返回晦气的404,存在则读取该资源,不留神出错返回500,反之通过请求头的if-modified-since判断是否已缓存,已缓存返回304,反之由zlib压缩之,以管道方式返回资源,状态码自然是200了;下面是粗制的代码片段,仅供参考:

if (req.method=='GET') {
        var pathname=url.parse(req.url).pathname;
        var realpath='';
        if (pathname==='/') {
            realpath='welcome.html';
        }else{
            realpath=path.join('dist',path.normalize(pathname.replace(/\.\./g,'')));
        }
        var extname=path.extname(realpath);
        extname=extname?extname.slice(1):'unknown';
        var type=mime[extname]||'text/plain';

        fs.exists(realpath,function(exist){
            if(!exist){
                res.writeHead(404,{
                    'content-type':'text/plain'
                });
                res.write('The Resourse '+pathname+' was Not Found!');
                res.end();
            }else{
                fs.readFile(realpath,'binary',function(err,file){
                    if(err){
                        res.writeHead(500,{
                            'content-type':'text/plain'
                        });
                        res.end();
                    }
                    if(extname.match(config.fileMatch)){
                        var expires=new Date();
                        expires.setTime(expires.getTime()+config.maxAge*1000);
                        res.setHeader('Expires',expires.toUTCString());
                        res.setHeader('cache-control','max-age='+config.maxAge);
                    }
                    fs.stat(realpath,function(err,stat){
                        var lastModified=stat.mtime.toUTCString();
                        res.setHeader('Last-Modified',lastModified);

                        if(req.headers['if-modified-since']&&lastModified==req.headers['if-modified-since']){
                            res.writeHead(304,'ok');
                            res.end();
                        }else{
                            var raw=fs.createReadStream(realpath);
                            var acceptEncoding=req.headers['accept-encoding']||'';
                            var matched=extname.match(/css|js|html/ig);
                            if(matched&&acceptEncoding.match(/\bgzip\b/)){
                                res.writeHead(200,{
                                    'Content-Encoding':'gzip'
                                });
                                raw.pipe(zlib.createGzip()).pipe(res);
                            }else if(matched&&acceptEncoding.match(/\bdeflate\b/)){
                                res.writeHead(200,{
                                    'Content-Encoding':'deflate'
                                });
                                raw.pipe(zlib.createDeflate()).pipe(res);
                            }else{
                                res.writeHead(200,'ok');
                                raw.pipe(res);
                            }
                        }
                    });
                });
            }
        });
    }
}

勿取笑,看下重点,文件上传到静态资源服务器;这在另一个POST请求里:

else{
        var pathname=url.parse(req.url).pathname;
        if (pathname=='/upload.html') {
            var mainId=new Date().getTime();
                var form=new formidable.IncomingForm();
                form.encoding='utf-8';
                form.uploadDir =  'dist/'+url.parse(req.url,true).query.dir+'/';
                form.keepExtensions = true; 
                form.maxFieldsSize = 1000 * 1024 * 1024;
                var byted=null;
                form.on('error',function(err){
                    console.log(err);
                })
                .on('aborted',function(){
                    console.log('aborted');
                })
                .on('progress',function(bytesReceived, bytesExpected){
                    console.log(bytesReceived, bytesExpected);
                });

                form.parse(req,function(err,field,files){
                    if(err){console.log(err);}

                    var files=files.editUploadFile;
                    var newPath='......';
                    console.log('uploaded:'+newPath);
                    fs.renameSync(files.path,newPath);
                    res.end();
                });
        };
}

那么现在现在静态资源的请求就涉及到跨域问题了,不多说了,设置如下响应头:

res.writeHead(200,{
    'Access-Control-Allow-Origin':'*',
    "Access-Control-Allow-Headers":"X-Requested-With",
    "Access-Control-Allow-Methods":"PUT,POST,GET,DELETE,OPTIONS"
});

到此,静态资源服务器可以上线用了,加了缓存和压缩,更多对静态资源的处理,还在探索中……,

如果文件上传程序已搞定,基本上没什么大问题了,只是要注意跨域问题,主域和子域同时设置document.domain='famanoder.com';是一种方案,其他方案,尽情度娘吧!

npm社区如此火热强大,静态资源服务器自然少不了现成模块供君使用,推荐anywhere模块,只需安装模块,进入文件目录anywhere port即架起了一个静态服务器,方便不少呢!

博客地址:http://famanoder.com/bokes

本文为慕课网作者原创,转载请标明【原文作者及本文链接地址】。侵权必究,谢谢合作!
打开App,阅读手记
7人推荐
发表评论
随时随地看视频慕课网APP

热门评论

棒棒哒!好久没见你更新文章了

查看全部评论