转载

Express(4+)框架浅析1 --[app对象]

犹豫了好久,最终决定把express(4.13.3)写成一个系列,这样或许可以多拿点kpi。本人假设读者有一定nodejs基础并了解express的基本使用。无论如何,这里都先放上一个广告, 本人博客 ,为何在群里宣传了这么久,star却并没有增加-_-。

1.理解app

在使用Express的时候,通常会以如下方式创建一个应用:

var express require('express');   var app = express();   app.listen(3000);   

在不使用express的情况下,是这样做的:

var http = require('http');   http.createServer(function(req,res){     res.write('Hello world!');   res.end }).listen(3000); 

通过源码,不难发现express其实是一个 工厂函数 ,用来创建app:(express/lib/express.js)

function createApplication() {     var app = function(req, res, next) {     app.handle(req, res, next);   };    mixin(app, EventEmitter.prototype, false);   mixin(app, proto, false);    app.request = { __proto__: req, app: app };   app.response = { __proto__: res, app: app };   app.init();   return app; } 

express/lib/application.js:

app.listen = function listen() {     var server = http.createServer(this);   return server.listen.apply(server, arguments); }; 

因此,在使用express的时候,所有的请求都交给app.handle进行处理了,虽然router也有自己的处理逻辑,但也是可以看作app的一个小型示例,会有自己root节点,所以这里插播一条将来会讲到的router部分的内容:

//匹配 localhost/ app.get('/',function(req,req){});  //匹配localhost/list/   app.use('/list', router);   router.get('/',function(req,res){});   

2.模块依赖

虽然本人觉得这部分并不重要,但一开始即讲app内的方法,似乎有点突然,所以这里仅贴上源码的内容凑紫薯:

var finalhandler = require('finalhandler');   var Router = require('./router');   var methods = require('methods');   var middleware = require('./middleware/init');   var query = require('./middleware/query');   var debug = require('debug')('express:application');   var View = require('./view');   var http = require('http');   var compileETag = require('./utils').compileETag;   var compileQueryParser = require('./utils').compileQueryParser;   var compileTrust = require('./utils').compileTrust;   var deprecate = require('depd')('express');   var flatten = require('array-flatten');   var merge = require('utils-merge');   var resolve = require('path').resolve;   var slice = Array.prototype.slice;   

3.app初始化

var app = exports = module.exports = {};   

导出一个对象字面量,这里没什么好说的,init方法会扩展这个对象:

app.init = function init() {     this.cache = {};   this.engines = {};   this.settings = {};   this.defaultConfiguration(); }; 

通过源码可知,初始化cache,engines(模版引擎),settings之后,调用默认配置函数进行默认配置。

4.app.listen

listen方法很简单,使用apply函数调用http模块:

app.listen = function listen() {     var server = http.createServer(this);   return server.listen.apply(server, arguments); }; 

5.setting

app.set = function set(setting, val) {     if (arguments.length === 1) {     // app.get(setting)     return this.settings[setting];   }   debug('set "%s" to %o', setting, val);   // set value   this.settings[setting] = val;   // trigger matched settings   switch (setting) {     case 'etag':       this.set('etag fn', compileETag(val));       break;     case 'query parser':       this.set('query parser fn', compileQueryParser(val));       break;     case 'trust proxy':       this.set('trust proxy fn', compileTrust(val));       // trust proxy inherit back-compat       Object.defineProperty(this.settings, trustProxyDefaultSymbol, {         configurable: true,         value: false       });       break;   }   return this; }; 

很好理解,根据 arguments 的数量来读取或者进行设置。当选项是 etagquery parsertrust proxy 时,会进行额外的设置。

6.默认配置 defaultConfiguration

刚才说过,在执行init的时候会进行默认配置 defaultConfiguration

app.defaultConfiguration = function defaultConfiguration() {     var env = process.env.NODE_ENV || 'development';    // default settings   this.enable('x-powered-by');   this.set('etag', 'weak');   this.set('env', env);   this.set('query parser', 'extended');   this.set('subdomain offset', 2);   this.set('trust proxy', false);   // trust proxy inherit back-compat   Object.defineProperty(this.settings, trustProxyDefaultSymbol, {     configurable: true,     value: true   });   debug('booting in %s mode', env);   this.on('mount', function onmount(parent) {     // inherit trust proxy     if (this.settings[trustProxyDefaultSymbol] === true       && typeof parent.settings['trust proxy fn'] === 'function') {       delete this.settings['trust proxy'];       delete this.settings['trust proxy fn'];     }      // inherit protos     this.request.__proto__ = parent.request;     this.response.__proto__ = parent.response;     this.engines.__proto__ = parent.engines;     this.settings.__proto__ = parent.settings;   });   // setup locals   this.locals = Object.create(null);   // top-most app is mounted at /   this.mountpath = '/';   // default locals   this.locals.settings = this.settings;   // default configuration   this.set('view', View);   this.set('views', resolve('views'));   this.set('jsonp callback name', 'callback');   if (env === 'production') {     this.enable('view cache');   }   Object.defineProperty(this, 'router', {     get: function() {       throw new Error('/'app.router/' is deprecated!/nPlease see the 3.x to 4.x migration guide for details on how to update your app.');     }   }); }; 

这里做了几件事: 1.设置 x-powered-byetagenvquery parsersubdomain offset

2.注册 mount 事件回调。

3.增加 this.locals(用于保存全局环境变量)this.mountpath(保存当前挂载路径)

至此,express框架app的主要方法已经介绍完毕,其实express框架并不复杂,希望各位了解其原理之后可以在开发少跳坑,少挖坑,并且能在需要时快速开发出牛逼的插件。

7.下期预告:Express(4+)框架浅析2 --[router] 敬请期待

原文  http://ued.fanxing.com/express4-understanding-app-object/
正文到此结束
Loading...