Appearance
Express 源代码导览
项目结构
Express 的源代码结构如下:
express/
├── lib/
│ ├── application.js # 应用主类
│ ├── express.js # 入口文件
│ ├── request.js # 请求对象扩展
│ ├── response.js # 响应对象扩展
│ ├── router/
│ │ ├── index.js # 路由器主类
│ │ ├── layer.js # 路由层
│ │ └── route.js # 路由类
│ ├── middleware/ # 内置中间件
│ │ ├── query.js # 查询解析
│ │ ├── init.js # 初始化
│ │ └── ... # 其他中间件
│ ├── utils.js # 工具函数
│ ├── view.js # 视图渲染
│ └── ... # 其他模块
├── test/ # 测试文件
├── examples/ # 示例代码
├── docs/ # 文档
└── History.md # 更新日志核心文件详解
express.js
express.js 是 Express 的入口文件,负责:
- 导出主函数:创建应用实例的工厂函数
- 导出核心类:Application、Router、Request、Response
- 导出工具函数:各种辅助函数
关键代码片段:
javascript
// 创建应用实例
function express() {
return new Application();
}
// 导出核心类
express.Application = Application;
express.Router = Router;
express.Request = Request;
express.Response = Response;
// 导出工具函数
express.static = serveStatic;
express.json = bodyParser.json;
express.urlencoded = bodyParser.urlencoded;
module.exports = express;application.js
application.js 实现了 Express 应用类,主要功能包括:
- 应用初始化:设置默认配置
- 中间件注册:注册应用级中间件
- 路由注册:注册应用级路由
- 请求处理:处理传入的 HTTP 请求
- 服务器启动:启动 HTTP 服务器
关键代码片段:
javascript
class Application extends EventEmitter {
constructor() {
super();
this.settings = {};
this.engines = {};
this.defaultConfiguration();
}
// 默认配置
defaultConfiguration() {
this.set('env', process.env.NODE_ENV || 'development');
this.set('x-powered-by', true);
this.set('subdomain offset', 2);
this.set('trust proxy', false);
this.set('query parser', 'extended');
this.set('jsonp callback name', 'callback');
}
// 启动服务器
listen(port, hostname, backlog, callback) {
const server = http.createServer(this);
return server.listen(port, hostname, backlog, callback);
}
// 注册中间件
use(fn) {
let offset = 0;
let path = '/';
// 处理路径参数
if (typeof fn !== 'function') {
const arg = fn;
fn = arguments[offset++];
if (typeof fn !== 'function') {
throw new TypeError('Router.use() requires a middleware function');
}
path = arg;
}
const layer = new Layer(path, {}, fn);
layer.route = undefined;
this.stack.push(layer);
return this;
}
// 注册 GET 路由
get(path, ...handlers) {
this._route('get', path, handlers);
return this;
}
// 注册路由
_route(method, path, handlers) {
const route = this._router.route(path);
route[method].apply(route, handlers);
return this;
}
// 处理请求
handle(req, res, done) {
const router = this._router;
const finalHandler = done || finalhandler(req, res, {
env: this.get('env'),
onerror: this.onerror.bind(this)
});
router.handle(req, res, finalHandler);
}
}router/index.js
router/index.js 实现了路由器类,主要功能包括:
- 路由注册:注册各种 HTTP 方法的路由
- 路由匹配:匹配请求路径到对应的路由
- 参数提取:提取路径参数
- 中间件执行:执行路由中间件
关键代码片段:
javascript
class Router extends EventEmitter {
constructor() {
super();
this.params = {};
this._params = [];
this.caseSensitive = undefined;
this.mergeParams = undefined;
this.strict = undefined;
this.stack = [];
}
// 注册 GET 路由
get(path, ...handlers) {
this._route('get', path, handlers);
return this;
}
// 注册路由
_route(method, path, handlers) {
const route = this.route(path);
route[method].apply(route, handlers);
return this;
}
// 创建路由
route(path) {
const route = new Route(path);
const layer = new Layer(path, {}, route.dispatch.bind(route));
layer.route = route;
this.stack.push(layer);
return route;
}
// 处理请求
handle(req, res, done) {
let self = this;
let idx = 0;
let stack = self.stack;
let parentUrl = req.baseUrl || '';
let done = done || finalhandler(req, res, {
env: this.get('env'),
onerror: logerror
});
req.originalUrl = req.originalUrl || req.url;
req.baseUrl = parentUrl;
req.url = parentUrl + req.url;
function next(err) {
if (err === 'route') {
return done();
}
if (err === 'router') {
return done();
}
const layerError = err === 'route'
? null
: err;
// 移除尾随斜杠
const slashRemoved = trimSlash(req.url);
// 路由匹配
const layer = matchLayer(layer, slashRemoved, req);
if (!layer) {
return done(layerError);
}
// 处理路由
self.process_params(layer, layerError, req, res, function(err) {
if (err) {
return next(err);
}
if (layer.route) {
return layer.handle_request(req, res, next);
}
trim_prefix(layer, layerError, req, res, next);
});
}
next();
}
}router/layer.js
router/layer.js 实现了路由层类,主要功能包括:
- 路径匹配:匹配请求路径
- 参数提取:提取路径参数
- 中间件执行:执行中间件函数
关键代码片段:
javascript
class Layer {
constructor(path, options, fn) {
this.handle = fn;
this.name = fn.name || '<anonymous>';
this.params = undefined;
this.path = undefined;
this.regexp = pathRegexp(path, this.keys = [], options);
if (path === '/' && !this.regexp.fast_slash) {
this.regexp.fast_slash = true;
}
}
// 匹配路径
match(path) {
let match;
if (path != null) {
// 快速路径匹配
if (this.regexp.fast_slash) {
this.params = {};
this.path = '';
return true;
}
// 正则匹配
match = this.regexp.exec(path);
}
if (!match) {
return false;
}
// 提取参数
this.params = {};
this.path = match[0];
const keys = this.keys;
const params = this.params;
for (let i = 1; i < match.length; i++) {
const key = keys[i - 1];
const prop = key.name;
const val = decode_param(match[i]);
if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
params[prop] = val;
}
}
return true;
}
// 处理请求
handle_request(req, res, next) {
const fn = this.handle;
try {
fn(req, res, next);
} catch (err) {
next(err);
}
}
// 处理错误
handle_error(err, req, res, next) {
const fn = this.handle;
if (fn.length !== 4) {
return next(err);
}
try {
fn(err, req, res, next);
} catch (err) {
next(err);
}
}
}request.js
request.js 扩展了 Node.js 的 IncomingMessage,主要功能包括:
- 查询解析:解析查询字符串
- 参数访问:访问路径参数
- 属性访问:便捷的属性访问方法
关键代码片段:
javascript
const req = Object.create(http.IncomingMessage.prototype);
// 查询参数
Object.defineProperty(req, 'query', {
configurable: true,
enumerable: true,
get: function() {
const querystring = this._querystring || (this._querystring = parseUrl(this).query);
return this._query || (this._query = parseQuery(querystring));
},
set: function(val) {
this._query = val;
}
});
// 路径参数
Object.defineProperty(req, 'params', {
configurable: true,
enumerable: true,
get: function() {
return this._params;
},
set: function(val) {
this._params = val;
}
});
// 路由路径
Object.defineProperty(req, 'path', {
configurable: true,
enumerable: true,
get: function() {
return parseUrl(this).pathname;
}
});
// 检查请求类型
req.get = req.header = function header(name) {
const lc = name.toLowerCase();
switch (lc) {
case 'referer':
case 'referrer':
return this.headers.referrer || this.headers.referer || '';
default:
return this.headers[lc] || '';
}
};
// 检查内容类型
req.is = function(types) {
const arr = types;
const type = this.get('Content-Type');
if (!type) {
return false;
}
if (!Array.isArray(types)) {
types = arr = [types];
}
for (let i = 0; i < types.length; i++) {
if (typeis(type, types[i])) {
return types[i];
}
}
return false;
};
module.exports = req;response.js
response.js 扩展了 Node.js 的 ServerResponse,主要功能包括:
- 状态码设置:设置 HTTP 状态码
- 响应头发送:设置和发送响应头
- 响应体发送:发送各种格式的响应体
- 模板渲染:渲染模板引擎
关键代码片段:
javascript
const res = Object.create(http.ServerResponse.prototype);
// 设置状态码
res.status = function status(code) {
this.statusCode = code;
return this;
};
// 设置响应头
res.set = res.header = function header(field, val) {
if (arguments.length === 2) {
const value = Array.isArray(val) ? val.map(String) : String(val);
const name = typeof field === 'string'
? field.toLowerCase()
: field;
this.setHeader(name, value);
} else {
for (const key in field) {
this.set(key, field[key]);
}
}
return this;
};
// 发送响应
res.send = function send(body) {
const chunk = body;
const encoding = 'utf8';
const req = this.req;
const type = this.get('Content-Type');
// 设置状态码
this.statusCode = this.statusCode || 200;
// 发送 JSON
if (Buffer.isBuffer(body)) {
if (!type) {
this.set('Content-Type', 'application/octet-stream');
}
this.end(chunk);
} else if (typeof body === 'string') {
if (!type) {
this.set('Content-Type', 'text/html');
}
this.end(chunk, encoding);
} else if (typeof body === 'object') {
if (body === null) {
body = null;
} else if (Buffer.isBuffer(body)) {
if (!type) {
this.set('Content-Type', 'application/octet-stream');
}
} else {
return this.json(body);
}
} else {
this.end(chunk, encoding);
}
return this;
};
// 发送 JSON
res.json = function json(obj) {
const body = JSON.stringify(obj);
if (!this.get('Content-Type')) {
this.set('Content-Type', 'application/json');
}
return this.send(body);
};
// 渲染模板
res.render = function render(view, options, callback) {
const app = this.req.app;
const done = callback || finalhandler(this.req, this.res, {
env: app.get('env'),
onerror: logerror
});
options = options || {};
// 渲染视图
app.render(view, options, (err, str) => {
if (err) {
return done(err);
}
this.send(str);
});
};
module.exports = res;关键算法
路由匹配算法
路由匹配使用正则表达式和参数提取:
javascript
function pathRegexp(path, keys, options) {
options = options || {};
const sensitive = options.sensitive;
const strict = options.strict;
const end = options.end !== false;
const delimiter = options.delimiter || '/';
const endsWith = [].concat(options.endsWith || []).map(escapeString).filter(Boolean);
// 转义特殊字符
let route = '';
let last = 0;
let isEndDelimited = false;
for (let i = 0; i < path.length; i++) {
const char = path[i];
if (char === '*') {
// 通配符
route += escapeRegExp(last, path, i) + '((?:.*))';
isEndDelimited = true;
last = i + 1;
} else if (char === ':') {
// 参数
const name = getName(path, i);
const pattern = getPattern(path, i);
route += escapeRegExp(last, path, i) + '(?:' + pattern + ')';
keys.push({ name, optional: false, offset: i });
i += name.length + pattern.length;
last = i + 1;
}
}
route += escapeRegExp(last, path, path.length);
// 添加结束匹配
if (end) {
if (!strict) {
route += '(?:' + delimiter + ')?';
}
if (!isEndDelimited) {
for (let i = 0; i < endsWith.length; i++) {
route += '(?=' + endsWith[i] + ')';
}
}
}
return new RegExp('^' + route + '$', sensitive ? '' : 'i');
}中间件执行算法
中间件使用链式调用模式:
javascript
function handle(req, res, done) {
let idx = 0;
const stack = this.stack;
function next(err) {
if (err) {
// 错误处理
return done(err);
}
if (idx >= stack.length) {
// 所有中间件执行完毕
return done();
}
const layer = stack[idx++];
// 匹配路径
if (!layer.match(req.url)) {
return next();
}
// 执行中间件
try {
layer.handle_request(req, res, next);
} catch (err) {
next(err);
}
}
next();
}性能关键点
1. 路由匹配优化
Express 使用正则表达式缓存和快速路径匹配:
- 正则缓存:编译后的正则表达式被缓存
- 快速路径:根路径使用快速匹配
- 参数提取:高效的参数提取算法
2. 中间件执行优化
中间件执行通过以下方式优化:
- 最小化开销:每个中间件只做一件事
- 提前终止:可以提前终止中间件链
- 错误处理:专门的错误处理中间件
3. 请求/响应优化
请求和响应对象通过以下方式优化:
- 延迟计算:属性按需计算
- 缓存结果:计算结果被缓存
- 链式调用:支持方法链式调用
扩展点
1. 自定义中间件
Express 允许编写自定义中间件:
javascript
function customMiddleware(req, res, next) {
// 处理请求
req.customProperty = 'value';
// 继续执行
next();
}
app.use(customMiddleware);2. 自定义路由
Express 支持自定义路由:
javascript
const router = express.Router();
router.get('/custom', (req, res) => {
res.send('Custom route');
});
app.use('/api', router);3. 自定义错误处理
Express 支持自定义错误处理:
javascript
function errorHandler(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
}
app.use(errorHandler);测试策略
Express 使用多种测试策略:
- 单元测试:测试单个函数和模块
- 集成测试:测试模块之间的交互
- 端到端测试:测试完整的请求-响应流程
- 性能测试:使用 benchmark 进行性能测试
总结
Express 的源代码展示了其简洁而强大的设计。通过中间件链、路由系统和扩展的请求/响应对象,Express 提供了一个强大而灵活的 Web 框架。理解 Express 的源代码结构有助于我们深入理解其工作原理,并更好地使用和扩展 Express。

扫描二维码关注"架构师AI杜"公众号,获取更多技术内容和最新动态
