一个简单的服务器
先从手写一个简单的服务器入手,用小步走的方式一步步实现完善 express 的架构。
const http = require('http');
const url = require('url');
// 假设这个是路由系统
const Router = [
{
path: '*',
method: '*',
handler(req, res) {
res.end(`Cannot ${req.method} ${req.url}`)
}
}
]
// 创建应用
function createApplication() {
return {
// 应用的 get 方法
get(url, handler) {
Router.push({
path: url,
method: 'get',
handler,
})
},
// 服务器监听方法
listen() {
const server = http.createServer((req, res) => {
const { pathname } = url.parse(req.url);
for(let i = 1; i < Router.length; i++) {
const { path, method, handler } = Router[i];
if(pathname === path && method === req.method.toLowerCase()) {
handler(req, res);
}
}
});
server.listen(...arguments);
}
}
}
分层设计
express.js-主入口
主入口 express.js 写 createApplication 方法并导出。
const Application = require('./application');
function createApplication() {
return new Application;
}
module.exports = createApplication;
application.js-创建应用
创建应用的过程由 apllication.js 负责。
application.js 返回一个 Application 类,原型写 app 的方法。
暂时 Application 内部维护 router
const http = require('http');
const url = require('url');
function Application() {
this._router = {
path: '*',
method: '*',
handler(req, res) {
res.end(`Cannot ${req.method} ${req.url}`)
}
}
}
Application.prototype.get = function(url, handler) {
this_router.push({
path: url,
method: 'get',
handler,
})
}
Application.prototype.listen = function() {
const server = http.createServer((req, res) => {
const { pathname } = url.parse(req.url);
for(let i = 1; i < this._router.length; i++) {
const { path, method, handler } = this._router[i];
if(pathname === path && method === req.method.toLowerCase()) {
return handler(req, res);
}
return this._router[0].handler(req, res);
}
});
server.listen(...arguments);
}
module.exports = Application;
应用系统和路由系统分离
层级划分
各层引用关系
各层级数据结构
应用系统
Application 层
const http = require('http');
const url = require('url');
const Router = require('./router');
function Application() {
this._router = new Router();
}
Application.prototype.get = function(url, ...handlers) {
// 调用路由系统内部方法处理
this._router.get(url, handlers);
}
Application.prototype.listen = function() {
const server = http.createServer((req, res) => {
const done = () => {
if(req.method !== 'GET' || req.url !== '/favicon.ico') {
console.log(`Cannot ${req.method} ${req.url}`);
res.end(`Cannot ${req.method} ${req.url}`);
}
}
// 路由的事情交给路由自己处理
this._router.handler(req, res, done);
});
server.listen(...arguments);
}
module.exports = Application;
路由系统
Router 层
const url = require('url');
const Route = require('./route');
const Layer = require('./layer');
function Router() {
this.stack = []; // 存放 layer 层
}
// 建立 Layer 和 Route 的关系
Router.prototype.route = function(path) {
const route = new Route();
const layer = new Layer(path, route.dispatch.bind(route));
layer.route = route;
// 把layer添加到stack
this.stack.push(layer);
return route;
}
Router.prototype.get = function(path, handlers) {
const route = this.route(path);
route.get(handlers);
}
Router.prototype.handler = function(req, res, out) {
let idx = 0;
const next = () => {
// 超出递归边界,执行外层传过来的 out(即执行 application 传过来的 done),最终退出
if(idx >= this.stack.length) return out();
const { pathname } = url.parse(req.url);
const layer = this.stack[idx++];
// 外层 layer 匹配 path
if(layer.path === pathname) {
// 处理 layer 层的 route
layer.handle_request(req, res, next);
} else {
// 不匹配就走下一个 layer 层
next();
}
}
next();
}
module.exports = Router;
Layer 层
function Layer(path, handler) {
this.path = path;
this.handler = handler;
}
Layer.prototype.handler = function(req, res, next) {
this.handler(req, res, next);
}
Layer.prototype.handle_request = function(req, res, next) {
this.handler(req, res, next)
}
module.exports = Layer;
Route 层
const Layer = require('./layer');
function Route() {
this.stack = []; // 存放 layer 层
}
Route.prototype.get = function(handlers) {
handlers.forEach(handler => {
// 这个 Layer 类接收的第一个参数 path 可以看作是占位,没实际用处,因为内层只根据 method 匹配
const layer = new Layer('/', handler);
layer.method = 'get';
this.stack.push(layer);
});
}
Route.prototype.dispatch = function(req, res, out) {
let idx = 0;
const next = () => {
// 超出递归边界,执行外层传过来的 out(即执行外层的下一个layer),退出内层
if(idx >= this.stack.length) return out();
const layer = this.stack[idx++];
// 内层 layer 匹配 method
if(layer.method === req.method.toLowerCase()) {
layer.handle_request(req, res, next);
} else {
next();
}
}
next();
}
module.exports = Route;
测试
const express = require('./lib/express');
const app = express();
app.get('/', function(req, res, next) {
console.log('get / 1-1');
next();
}, function(req, res, next) {
console.log('get / 1-2');
next();
}, function(req, res, next) {
console.log('get / 1-3');
// res.end('Hello ');
next();
},);
app.get('/', function(req, res, next) {
console.log('get / 2-1');
res.end('get / 2-1')
})
app.listen(3005);
结果
总结
-
Application 是 express 的整个的应用系统,内部放置了一个路由系统
-
Application 和 Router 分离
-
express 的路由系统划分了 Router、Layer、Route 三个类,中间件的调用一共分为内外两层判断,外层过滤 path,内层过滤 method
-
express 原理思路