【问题标题】:Node.js HTML5 Boilerplate Server Config IntegrationNode.js HTML5 样板服务器配置集成
【发布时间】:2012-08-11 03:04:54
【问题描述】:

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

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

【问题讨论】:

    标签: node.js express html5boilerplate


    【解决方案1】:

    Most of the file 由一系列函数组成,这些函数为符合 Connect 中间件规范的框架(如 Express)生成中间件。第二个代码清单旨在创建一个使用所有这些功能的 HTTP 服务器。据我所知,您似乎应该传入通常称为createServer 的任何内容,h5bp 将为您完成创建和设置。例如,如果您通常会这样做:

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

    您将改为将express 传递给h5bp.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');
    

    【讨论】:

    • 感谢您的回复,内容非常丰富。正如您所说,由于提供的脚本与 Express 3 不兼容,我想我只会尝试自己复制该功能。再次感谢您提供简洁、信息丰富且快速的回复。
    • 很高兴能帮上忙。在查看脚本时,您可能会发现,每个中间件都是非常独立且易于解释的,而且实现起来并不难。 (事实上​​,我意识到我在最近的一个项目中忘记重定向www. 流量,并使用他们的技术修改来实现它。)
    【解决方案2】:

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

    存储库已移至此处: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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-31
      • 2019-06-20
      • 2018-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-08
      相关资源
      最近更新 更多