3

我正在设置一个将使用 Node.js 和 Express 构建的新项目的结构。我使用HTML5 Boilerplate作为最佳起点。自带多种服务器的配置文件:Apache、Nginx、Node.js等。以下是HTML5 Boilerplate团队提供的Node.js服务器配置文件:

/* 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 并不完全处于初学者水平,但我也不会说我很先进。这段代码超出了我的范围。任何关于我可以阅读、观看或做什么的指示,以了解我在这里显然缺少的内容,将不胜感激。

4

2 回答 2

5

大部分文件由一系列函数组成,这些函数为框架(如 Express)生成符合 Connect 中间件规范的中间件。第二个代码清单旨在创建一个使用所有这些功能的 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 服务器,因此您无需createServer调用express; 相反,您应该只调用express()然后将结果传递给http.createServer. (有关详细信息,请参阅Express wiki 上从 2.x 迁移到 3.x 中的“应用程序功能” 。)这意味着此脚本与最新版本的 Express 不兼容。

[更新]

如果您查看testGitHub 上的目录,您可以看到一个示例应用程序

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');
于 2012-08-11T04:58:18.450 回答
1

node.js对h5bp进行了重大更新。
您现在可以将其用作快速中间件。

存储库已移至此处: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);
于 2013-03-01T22:57:16.143 回答