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

Nodejs基于Express4的动态页面静态化

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

上个星期在慕课网上提了个问:Express4开发的动态页面访问好慢的说?不幸的是并没有得到可行的回答,周末自己折腾了一番,一并将小站(花满楼)的几个页面全部静态化了;事后想了想,虽不是什么特别标准好的搞法,但纠结这么久了,这个问题终于有办法了,还是有些欣慰的;

一开始页面都是动态的,由jade模板render出来的,可不明白为什么不论页面内容多少,打开都至少要一秒多。。。;后来专门弄个站点作为静态资源站,缓存加gzip(Nodejs打造静态资源服务器与文件上传);OK,静态资源现在没啥大问题了;可是页面打开速度并不理想,那后台再压一遍吧,来个app.use(compress());事实证明并没啥明显效果;郁闷的我刚学点Nodejs,咋就碰到这无语的问题呢,百度好久,呵呵。。。最后只想到一个办法了,参照静态资源站的搞法,将jade编译成html,把动态页面转成静态资源来对待,会不会像加载静态资源一样快呢!答案是肯定的!!!

就我的博客站点来说,现在面临两个问题:一是直接将原来的jade编译,保留动态数据;二是现将动态数据剔除,再编译为html,由ajax页面加载后请求数据;我选择了前者,因为这样能在静态页面上保留最新的数据,而后者由js后面渲染上去的对SEO很不好;呵呵,而实际上这两种方法我都没用,因为就这点水平来说,在express的框架里,并没听说这种搞法,我自然就无从下手了,只是理想上的可行方案;

那咋办呢?好吧,原谅我选择了放弃express内置的模板,稍作整理后,Gulp(gulp-jade模块)直接将那些jade全编译为html(前端自动化之神器 — Gulp),我是这样想的,将这些编译后的html做为一种类似模板的模块,在routes里还是原来那样拿数据,将拿到的数据作为变量传递到html类模板那个模块对应的接口,然后将返回的html生成一个真正的静态页面,这样,原来的jade,在router不变的情况下,直接生成到对应目录了;上面说过要像加载静态资源一样加载页面,才可能够快;

Gulpfile.js

var jade=require('gulp-jade');

gulp.task('jade',function() {
    gulp.src('./views/bokeDetail.jade')
        .pipe(jade({pretty:true}))
        .pipe(gulp.dest('./public/famanoder/')); 
});

bokeDetail.templ.js

var html=function(id,title,subtitle,time,from,contents){
         //传递动态数据
         return '<html><head></head><body>'+动态数据+'</body></html>';
}
//片段,实际情况而定

module.exports=html;
bokeDetail.js(router)

//......
//引入对应静态模块
var boketempl=require('./templs/bokeDetail.templ.js);

//依旧读取数据
//传递数据:如,id,title,content,comments
//生成静态页面到指定目录
function createStaticPage(id,title,content,comments,fn){
                var path='./public/famanoder/';
                var html=boketempl(id,title,content,comments);
                var ws=fs.createWriteStream(path+id+'.html');
        ws.write(html,function(err) {
            console.log('writePage:'+path+id+'.html');
            fn&&fn();
        });
        ws.on('drain',function() {
            ws.end();
        });
}

ok,程序执行后静态页面就会带着动态数据生成到public下的famanoder目录了;下面还是在bokeDetail.js(router)里将response直指上面生成的静态页面;

var pathname=url.parse(req.url).pathname;
        var realpath='./public/famanoder/'+pathname.substr(pathname.lastIndexOf('/')+1)+'.html';
        var type='text/html';
        var extname='html';
        fs.exists(realpath,function(exist){
            if(!exist){console.log(101);
                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){
                    console.log(11);
                    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']){
                            console.log(0);
                            res.writeHead(304,{
                                'content-type':type
                            });
                            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/)){
                                console.log(1);
                                res.writeHead(200,{
                                    'content-type':type,
                                    'Content-Encoding':'gzip'
                                });
                                raw.pipe(zlib.createGzip()).pipe(res);
                            }else if(matched&&acceptEncoding.match(/\bdeflate\b/)){
                                console.log(2);
                                res.writeHead(200,{
                                    'content-type':type,
                                    'Content-Encoding':'deflate'
                                });
                                raw.pipe(zlib.createDeflate()).pipe(res);
                            }else{
                                console.log(3);
                                res.writeHead(200,{
                                    'content-type':type
                                });
                                raw.pipe(res);
                            }
                        }
                    });
                });
            }
        });

再次访问详情页,看看秒开了吧,纯静态的,路由没变,url没改,维护也很简单,只要改下bokeDetail.templ.js就可以了;没办法啊,可能在大侠眼里这样很愚蠢,就当逗您一笑吧;类似这种搞法,现在小站全部页面都静态化了,而且完全照顾到了SEO;

好吧,其实还遗留了一个重要问题:就博客详情来说,原来如果有大批博客,现在怎么批量转呢,其实我是在博客编辑好后提交时顺便生成静态页面的,为了详情页再快点。。。;问题来了,在这之前如果我有几百上千篇博客(当然我这个小前端还远没达到这么丰硕的成果),我不得每篇博客重新编辑提交一次;吓死宝宝了啊,别急,新建一个update.js直接批量生成吧,快的很!

Artical
    .find({}).exec(function(err,docs) {
        update(err,docs);
    });

    function update(err,docs) {
        err&&console.log(err);
        for(var i=0;i<docs.length;i++){
            (function(i){
                createStaticFile(docs[i]._id,docs[i].title,docs[i].subtitle,docs[i].time,docs[i].from,docs[i].contents,function() {
                    console.log((i+1)+'/'+docs.length+':updated');
                    if (i==docs.length-1) {
                        res.render('page/fifity',{
                            title:'updateBokes',
                            docs:docs.length
                        });
                    };
                })
            })(i);
        }
    }

其他牛逼启动更新的方式就不多讲了,

那么该轮到优化服务器和数据库了吧;好吧。。。我后端渣渣,服务器更不谈了,暂且就这样吧,毕竟几十块钱的服务器;小前端刚学Nodejs,诸多不足,望大侠路过指导;晚安!


本文出自慕课网,转载请注明出处,侵权必究。


打开App,阅读手记
6人推荐
发表评论
随时随地看视频慕课网APP

热门评论

有木有源码呀 后端渣渣学习

var boketempl=require('./templs/bokeDetail.templ.js);
这里是不是少了个单引号?后面的内容 全是string高亮  看得不太舒服

长得帅写得也好的人不多了。

查看全部评论