w3ctech

在thinkjs中实现Gzip压缩和静态文件缓存

在thinkjs中实现Gzip压缩和静态文件缓存

thinkjs在作者 welefen的努力下即将支持 目前需要实现Gzip压缩需要在github上下载最新版的thinkjs

修改core/View.js的 31-71行附近

 /**
     * 输出模版文件内容
     * @param  {[type]} templateFile [description]
     * @param  {[type]} charset      [description]
     * @param  {[type]} contentType  [description]
     * @param  {[type]} content      [description]
     * @return {[type]}              [description]
     */
    display: function(templateFile, charset, contentType){
      var self = this;
      return tag('view_init', this.http).then(function(){
        return self.fetch(templateFile);
      }).then(function(content){
        return self.render(content, charset, contentType).then(function(){
            return tag('view_end', self.http, content);
        });
      }).then(function(){
        return self.http.end();
      }).catch(function(err){
        console.error(err.stack);
        return self.http.end();
      });
    },
    /**
     * 渲染模版
     * @param  {[type]} content     [description]
     * @param  {[type]} charset     [description]
     * @param  {[type]} contentType [description]
     * @return {[type]}             [description]
     */
    render: function(content, charset, contentType){
      if (!this.http.cthIsSend) {
        charset = charset || C('encoding');
        contentType = contentType || C('tpl_content_type');
        this.http.setHeader('Content-Type', contentType + '; charset=' + charset);
      }
      if (C('show_exec_time')) {
        this.http.sendTime('Exec-Time');
      }
     return this.http.echo(content || '', charset || C('encoding'));
    },

修改 core/Controller.js 的340行左右

 /**
     * 结束输出,输出完成时一定要调用这个方法
     * @param  {[type]} obj [description]
     * @return {[type]}     [description]
     */
    end: function(obj, encoding) {
      var self=this;
      if (obj !== undefined) {
        self.echo(obj, encoding).then(function(){
            self.http.end();
        });
      }else{
        self.http.end();
      }
    },

这些相信不久welefen会修改的。 接下来实现tag行为 GzipContentBehavior.js. 我注释掉了deflate压缩去掉注释就可以实现deflate压缩,把文件放到App/Lib/Behavior下面

var zlib = require('zlib');

/**
 * Gzip压缩
 */
module.exports = Behavior(function () {
    return {
        run: function (content) {
            var self = this;
            var deferred = getDefer();
            //            if (self.http.headers["accept-encoding"].indexOf("deflate") != -1) {
            //                self.deflate(content, self.http, deferred);
            //            } else if (self.http.headers["accept-encoding"].indexOf("gzip") != -1) {
            //                self.gzip(content, self.http, deferred);
            //            } else {
            //                return content;
            //            }
            if (self.http.headers["accept-encoding"].indexOf("gzip") != -1) {
                self.gzip(content, self.http, deferred);
            } else {
                return content;
            }
            return deferred.promise;
        },
        gzip: function (content, http, deferred) { //检测是否是手机访问
            zlib.gzip(content, function (err, data) {
                if (!err) {
                    http.res.setHeader("Content-Encoding", "gzip");
                    deferred.resolve(data);
                } else {
                    deferred.resolve(content);
                }
            });
        },
        deflate: function (content, http, deferred) { //检测是否是手机访问
            zlib.deflate(content, function (err, data) {
                if (!err) {
                    http.res.setHeader("Content-Encoding", "deflate");
                    deferred.resolve(data);
                } else {
                    deferred.resolve(content);
                }
            });
        },
    }
})

然后在App/Conf/tag.js里面配置一下

//行为
module.exports = {
    resource_check: ['CheckResource'],
    content_write:['GzipContent']
}

看到了CheckResource,它是实现静态文件gzip压缩和缓存的.它使用mime库所以需要npm install mime一下

var fs = require('fs');
var mime = require('mime');
var path = require("path");
var zlib = require('zlib');

/**
 * 静态资源请求
 * @return {[type]} [description]
 */
module.exports = Behavior(function () {
    'use strict';
    return {
        options: {
            'url_resource_on': false
        },
        run: function () {
            if (!RESOURCE_PATH || !this.options.url_resource_on || !this.http.pathname) {
                return false;
            }
            var pathname = this.http.pathname;
            if (pathname.indexOf('/') === 0) {
                pathname = pathname.substr(1);
            }
            var reg = C('url_resource_reg');
            //通过正则判断是否是静态资源请求
            if (!reg.test(pathname)) {
                return false;
            }

            var file = RESOURCE_PATH + '/' + pathname;
            var res = this.http.res;
            var req = this.http.req;
            fs.stat(file, function (err, stats) {
                if (err) {
                    res.statusCode = 404;
                    res.end();
                } else {
                    var contentType = mime.lookup(file);
                    var exp_maxage = C('expires_maxAge') || 30 * 24 * 3600;
                    var expires = new Date();
                    var lastModified = stats.mtime.toUTCString();
                    var ifModifiedSince = "If-Modified-Since".toLowerCase();
                    var acceptEncoding = "Accept-Encoding".toLowerCase();
                    expires.setTime(expires.getTime() + exp_maxage * 1000);
                    res.setHeader('Content-Type', contentType || "text/plain");
                    res.setHeader("Cache-Control", "max-age=" + exp_maxage);
                    res.setHeader("Expires", expires.toUTCString());
                    res.setHeader("Last-Modified", lastModified);
                    if (req.headers[ifModifiedSince] && lastModified == req.headers[ifModifiedSince]) {
                        res.writeHead(304, "Not Modified");
                        res.end();
                    } else {
                        var fileStream = fs.createReadStream(file);
                        if ((req.headers[acceptEncoding] || '').indexOf('gzip') != -1&&contentType.match(/(javascript|css)/)) {
                            res.setHeader('Content-Encoding', 'gzip');
                            var gzip = fileStream.pipe(zlib.createGzip());
                            gzip.pipe(res);
                            gzip.on('end', function () {
                                res.end();
                            });
                        }else {
                            fileStream.pipe(res);
                            fileStream.on('end', function () {
                                res.end();
                            });
                        }
                    }
                }
            });
            //返回一个pendding promise, 不让后续执行
            return getDefer().promise;
        }
    };
});

至此我们就完成了thinkjs的gzip和浏览器缓存的功能。 刚刚接触thinkjs不久,如果代码中有的地方不对。还望海涵。

w3ctech微信

扫码关注w3ctech微信公众号

共收到2条回复

  • 学习了哈

    不过这个排版怎么这样呢?怎么到处用引用呢?还在头部加了一个标题,哈哈

    回复此楼
  • 最好通过配置项开启

    回复此楼