nodejs express 框架解密2-如何创建一个app
本文是基于express 3.4.6 的
1.在我们的app.js 文件里面有这么几行
http.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); });
这个其实是调用http模块 的 createServer 函数创建一个服务,然后监听端口的。
2. 我们再去看看express 的入口文件
/** * Module dependencies. */ var connect = require('connect') , proto = require('./application') , Route = require('./router/route') , Router = require('./router') , req = require('./request') , res = require('./response') , utils = connect.utils; /** * Expose `createApplication()`. */ exports = module.exports = createApplication; /** * Expose mime. */ exports.mime = connect.mime; /** * Create an express application. * * @return {Function} * @api public */ function createApplication() { var app = connect(); //将application中的方法全部拷贝到connect对象上去。 utils.merge(app, proto); //设置app 的request对象的原型为req,本身的属性为connect对象 app.request = { __proto__: req, app: app }; //设置app的response对象原型为res ,本身的属性为connect对象 app.response = { __proto__: res, app: app }; //调用application中的方法init app.init(); return app; } /** * Expose connect.middleware as express.* * for example `express.logger` etc. */ /** * 加载connect模块中得所有中间件 */ for (var key in connect.middleware) { Object.defineProperty( exports , key , Object.getOwnPropertyDescriptor(connect.middleware, key)); } /** * Error on createServer(). */ /** * 将创建服务器的方法输出 * @returns {Function} */ exports.createServer = function(){ console.warn('Warning: express.createServer() is deprecated, express'); console.warn('applications no longer inherit from http.Server,'); console.warn('please use:'); console.warn(''); console.warn(' var express = require("express");'); console.warn(' var app = express();'); console.warn(''); //加载创建应用程序的方法,开始创建application return createApplication(); }; /** * Expose the prototypes. */ exports.application = proto; exports.request = req; exports.response = res; /** * Expose constructors. */ exports.Route = Route; exports.Router = Router; // Error handler title exports.errorHandler.title = 'Express';
可以看到exports = module.exports = createApplication;将这个作为模块导出了,作为一个构造函数。
这个函数是:
function createApplication() { var app = connect(); //将application中的方法全部拷贝到connect对象上去。 utils.merge(app, proto); //设置app 的request对象的原型为req,本身的属性为connect对象 app.request = { __proto__: req, app: app }; //设置app的response对象原型为res ,本身的属性为connect对象 app.response = { __proto__: res, app: app }; //调用application中的方法init app.init(); return app; }
首先调用connect 组件app,于是将proto 上该有的方法都拷贝到app上去。proto是神马么?它就是 proto = require('./application') application.js 输出的“app” 对象 所有得函数,
接着将req,res 作为 组件app 的request,response 的原型,同时将app作为他们的一个属性,为什么要这么做呢?后面就会看到。最后调用app.init()方法,这个其实是调用application
中的init方法。
3.application.js
app.init = function(){ this.cache = {}; this.settings = {}; this.engines = {}; //默认配置 this.defaultConfiguration(); };
我们看到他是直接调用defaultConfiguration 方法的。我们再去看看defaultConfiguration方法的实现
app.defaultConfiguration = function(){ // default settings this.enable('x-powered-by'); this.enable('etag'); this.set('env', process.env.NODE_ENV || 'development'); this.set('subdomain offset', 2); debug('booting in %s mode', this.get('env')); // implicit middleware //调用中间件 this.use(connect.query()); this.use(middleware.init(this)); // inherit protos //继承原型 this.on('mount', function(parent){ this.request.__proto__ = parent.request; this.response.__proto__ = parent.response; this.engines.__proto__ = parent.engines; this.settings.__proto__ = parent.settings; }); //router //路由 this._router = new Router(this); this.routes = this._router.map; this.__defineGetter__('router', function(){ this._usedRouter = true; this._router.caseSensitive = this.enabled('case sensitive routing'); this._router.strict = this.enabled('strict routing'); return this._router.middleware; }); // setup locals this.locals = locals(this); // default locals this.locals.settings = this.settings; // default configuration this.set('view', View); this.set('views', process.cwd() + '/views'); this.set('jsonp callback name', 'callback'); this.configure('development', function(){ this.set('json spaces', 2); }); this.configure('production', function(){ this.enable('view cache'); }); };
从代码中可以看到,它首先调用中间件,中间件的作用主要是改写改写request,response 请求的。将这2个请求导出,方便后面的模板渲染。然后再调用路由模块。路由模块只要是根据path
调用路由分发函数分发路由,执行callback,最后调用view 模块,渲染我们的模板。
分类:
nodejs
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?