2012-08-11 75 views
3

我正在設置將使用Node.js和Express構建的新項目的結構。我正在使用HTML5 Boilerplate作爲最佳起點。它配備了多種類型的服務器的配置文件:阿帕奇,Nginx的,Node.js的,等等。以下是HTML5的樣板團隊提供的Node.js server configuration fileNode.js HTML5 Boilerplate服務器配置集成

/* h5bp server-configs project 
* 
* maintainer: @xonecas 
* contributors: @niftylettuce 
* 
* NOTES: 
* compression: use the compress middleware provided by connect 2.x to enable gzip/deflate compression 
*       http://www.senchalabs.org/connect/compress.html 
* 
* concatenation: use on of the following middlewares to enable automatic concatenation of static assets 
*        - https://github.com/mape/connect-assetmanager 
*        - https://github.com/TrevorBurnham/connect-assets 
*/ 
var h5bp = module.exports, 
    _http = require('http'), 
    _parse = require('url').parse; 

// send the IE=Edge and chrome=1 headers for IE browsers 
// on html/htm requests. 
h5bp.ieEdgeChromeFrameHeader = function() { 
    return function (req, res, next) { 
     var url = req.url, 
     ua = req.headers['user-agent']; 

     if (ua && ua.indexOf('MSIE') > -1 && /html?($|\?|#)/.test(url)) { 
     res.setHeader('X-UA-Compatible', 'IE=Edge,chrome=1'); 
     } 
     next(); 
    }; 
}; 

// block access to hidden files and directories. 
h5bp.protectDotfiles = function() { 
    return function (req, res, next) { 
     var error; 
     if (/(^|\/)\./.test(req.url)) { 
     error = new Error(_http.STATUS_CODES[405]); // 405, not allowed 
     error.status = 405; 
     } 
     next(error); 
    }; 
}; 

// block access to backup and source files 
h5bp.blockBackupFiles = function() { 
    return function (req, res, next) { 
     var error; 
     if (/\.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~/.test(req.url)) { 
     error = new Error(_http.STATUS_CODES[405]); // 405, not allowed 
     error.status = 405; 
     } 
     next(error); 
    }; 
}; 

// Do we want to advertise what kind of server we're running? 
h5bp.removePoweredBy = function() { 
    return function (req, res, next) { 
     res.removeHeader('X-Powered-By'); 
     next(); 
    }; 
}; 

// Enable CORS cross domain rules, more info at http://enble-cors.org/ 
h5bp.crossDomainRules = function() { 
    return function (req, res, next) { 
     res.setHeader('Access-Control-Allow-Origin', '*'); 
     res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With'); 
     next(); 
    }; 
}; 

// Suppress or force 'www' in the urls 
// @param suppress = boolean 
h5bp.suppressWww = function (suppress) { 
    return function (req, res, next) { 
     var url = req.url; 
     if (suppress && /^www\./.test(url)) { 
     res.statusCode = 302; 
     res.setHeader('Location', url.replace(/^www\./,'')); 
     } 
     if (!suppress && !/^www\./.test(url)) { 
     res.statusCode = 302; 
     res.setHeader('Location', "www."+url); 
     } 
     next(); 
    }; 
}; 

// Far expire headers 
// use this when not using connect.static for your own expires/etag control 
h5bp.expireHeaders = function (maxAge) { 
    return function (req, res, next) { 
     res.setHeader('Cache-Control', 'public, max-age='+ (maxAge)); 
     next(); 
    }; 
}; 

// Etag removal 
// only use this is you are setting far expires for your files 
// ** WARNING ** connect.static overrides this. 
h5bp.removeEtag = function() { 
    return function (req, res, next) { 
     res.removeHeader('Last-Modified'); 
     res.removeHeader('ETag'); 
     next(); 
    }; 
}; 

// set proper content type 
// @param mime = reference to the mime module (https://github.com/bentomas/node-mime) 
h5bp.setContentType = function (mime) { 
    return function (req, res, next) { 
     // I'm handling the dependency by having it passed as an argument 
     // we depend on the mime module to determine proper content types 
     // connect also has the same dependency for the static provider 
     // ** @TODO ** maybe connect/express expose this module somehow? 
     var path = _parse(req.url).pathname, 
     type = mime.lookup(path); 
     res.setHeader('Content-Type', type); 
     next(); 
    }; 
}; 

// return a express/connect server with the default middlewares. 
// @param serverConstructor = express/connect server instance 
// @param options = { 
// root: 'path/to/public/files', 
// maxAge: integer, time in miliseconds ex: 1000 * 60 * 60 * 24 * 30 = 30 days, 
// mime: reference to the mime module ex: require('mime') 
// } 
// Depends: 
// express or connect server 
// mime module [optional] 

h5bp.server = function (serverConstructor, options) { 
    var server = serverConstructor.createServer(), 
     stack = [ 
     this.suppressWww(true), 
     this.protectDotfiles(), 
     this.blockBackupFiles(), 
     this.crossDomainRules(), 
     this.ieEdgeChromeFrameHeader() 
     //,this.expireHeaders(options.maxAge), 
     // this.removeEtag(), 
     // this.setContentType(require('mime')) 
     ]; 
    // express/connect 
    if (server.use) { 
     stack.unshift(serverConstructor.logger('dev')); 
     stack.push(
     //serverConstructor.compress(), // express doesn't seem to expose this middleware 
     serverConstructor['static'](options.root, { maxAge: options.maxAge }), // static is a reserved 
     serverConstructor.favicon(options.root, { maxAge: options.maxAge }), 
     serverConstructor.errorHandler({ 
      stack: true, 
      message: true, 
      dump: true 
     }) 
    ); 
     for (var i = 0, len = stack.length; i < len; ++i) server.use(stack[i]); 
    } else { 
     server.on('request', function (req, res) { 
     var newStack = stack, 
      func; 
     (function next (err) { 
      if (err) { 
       throw err; 
       return; 
      } else { 
       func = newStack.shift(); 
       if (func) func(req, res, next); 
       return; 
      } 
     })(); 
     }); 
    } 
    return server; 
}; 

我的問題是:究竟如何做我去關於將此與Express整合?特別讓我困惑的部分代碼是底部:

// return a express/connect server with the default middlewares. 
// @param serverConstructor = express/connect server instance 
// @param options = { 
// root: 'path/to/public/files', 
// maxAge: integer, time in miliseconds ex: 1000 * 60 * 60 * 24 * 30 = 30 days, 
// mime: reference to the mime module ex: require('mime') 
// } 
// Depends: 
// express or connect server 
// mime module [optional] 

h5bp.server = function (serverConstructor, options) { 
    var server = serverConstructor.createServer(), 
     stack = [ 
     this.suppressWww(true), 
     this.protectDotfiles(), 
     this.blockBackupFiles(), 
     this.crossDomainRules(), 
     this.ieEdgeChromeFrameHeader() 
     //,this.expireHeaders(options.maxAge), 
     // this.removeEtag(), 
     // this.setContentType(require('mime')) 
     ]; 
    // express/connect 
    if (server.use) { 
     stack.unshift(serverConstructor.logger('dev')); 
     stack.push(
     //serverConstructor.compress(), // express doesn't seem to expose this middleware 
     serverConstructor['static'](options.root, { maxAge: options.maxAge }), // static is a reserved 
     serverConstructor.favicon(options.root, { maxAge: options.maxAge }), 
     serverConstructor.errorHandler({ 
      stack: true, 
      message: true, 
      dump: true 
     }) 
    ); 
     for (var i = 0, len = stack.length; i < len; ++i) server.use(stack[i]); 
    } else { 
     server.on('request', function (req, res) { 
     var newStack = stack, 
      func; 
     (function next (err) { 
      if (err) { 
       throw err; 
       return; 
      } else { 
       func = newStack.shift(); 
       if (func) func(req, res, next); 
       return; 
      } 
     })(); 
     }); 
    } 
    return server; 
}; 

我的JavaScript並不完全在初學者級別,但我也不會說我是先進的。這段代碼超越了我。任何關於我可以閱讀,觀看或做什麼的指針,瞭解我在這裏顯然想念的東西將不勝感激。

回答

5

Most of the file由一系列函數組成,這些函數生成符合Connect中間件規範的Express等框架中間件。第二個代碼清單旨在創建一個HTTP服務器,其中使用所有這些功能。從我所知道的情況來看,它看起來應該通過你通常所說的createServer,而h5bp會爲你創建和設置。例如,如果你通常會做:

var express = require('express'); 
var server = express.createServer(); 

你反而會傳遞expressh5bp.server,這對無論你在馬上蝙蝠通過調用createServer

var express = require('express'); 
var server = h5bp.server(express, options); 

一些設置後,它會檢查服務器是否具有名爲use(該行爲if (server.use))的功能,如果是,則使用該功能將其設置的所有中間件注入服務器。如果它不是,那麼它假定您正在使用原始Node.js HTTP服務器,並設置必要的代碼以手動傳遞請求通過stack中的每個項目(這是Connect/Express的作用您)。

值得注意的是,在Express 3(目前處於發佈候選階段)中,由Express創建的應用程序不再繼承自Node的HTTP服務器,因此您不需要在express上調用createServer;相反,您只需撥打express(),然後將結果傳遞給http.createServer。 (有關更多信息,請參閱Migrating from 2.x to 3.x on the Express wiki上的「應用程序功能」。)這意味着此腳本與Express的最新版本不兼容。

[更新]

如果你看看在GitHub上test目錄,你可以看到an example app

var express = require('express'), 
    h5bp  = require('../node.js'), 
    server = h5bp.server(express, { 
     root: __dirname, 
     maxAge: 1000 * 60 * 60 * 30 
    }); 

server.listen(8080); 
console.log('ok'); 
+0

感謝您的答覆,這是相當翔實。正如你所說,由於提供的腳本與Express 3不兼容,我想我只會嘗試自己複製這些功能。再次感謝您提供簡潔,翔實和快速的回​​復。 – 2012-08-11 05:50:37

+0

很高興有幫助。在查看腳本的同時,您可能會發現每個中間件都非常自包含,並且不言自明,而且實現起來也不那麼困難。 (事實上​​,我意識到我忘了在最近的一個項目中重定向流量,並使用他們的技術修改來實現它。) – 2012-08-11 06:22:55

1

h5bp爲node.js中的重大更新
您現在可以使用它作爲快遞中間件。

存儲庫已移到此處:https://github.com/h5bp/node-server-config

從文檔:

var express = require('express'), 
h5bp = require('h5bp'); 

var app = express(); 
// ... 
app.use(h5bp({ root: __dirname + '/public' })); 
app.use(express.compress()); 
app.use(express.static(__dirname + '/public')); 
// ... 
app.listen(3000);