// 中间件的概念 控制是否向下执行 (权限处理)// 中间件 可以扩展 req 和 res中的方法// 中间件 一般放在路由之前// 中间件 可以提前处理一些逻辑 和 koa 用法一样// express 中间 如果路由 完全匹配 、 以中间件路径开头 或者路径是/ 都可以匹配到const express = require('./express');const app = express();// express 中的中间件可以放置路径 这个路径的规则 和 cookie中path的一样 {path:'/a'} /app.use(function (req,res,next) { req.a = 1; next();})app.use('/',function (req, res, next) { req.a++; next();})app.use('/a', function (req, res, next) { req.a++; next();})app.get('/a',function (req,res,next) { res.end(req.a + '')})app.get('/', function (req, res, next) { res.end(req.a + '')})app.listen(3000);
const url = require('url');const Route = require('./route');const Layer = require('./layer');const methods = require('methods');function Router(){ this.stack = [];}Router.prototype.route = function (path) { let route = new Route(); let layer = new Layer(path,route.dispatch.bind(route)); // 给当前调用get方法 放入一层 layer.route = route; // 每个层都有一个route属性 标识他是一个路由 this.stack.push(layer); return route;}Router.prototype.use = function (path,handler) { // 中间件 会放到当前的路由系统中 if(typeof path === 'function'){ handler = path; // 给path默认值 path = '/' } let layer = new Layer(path,handler); // 产生一层 layer.route = undefined; // 如果route是undefind 说明他是中间件 this.stack.push(layer);}methods.forEach(method=>{ Router.prototype[method] = function (path, handlers) { // 用户调用get方法时 传递了多个处理函数 let route = this.route(path); // 构建一个route的 route[method](handlers); // 交给route 来存储用户的真正的handler }})Router.prototype.handle = function (req,res,out) { // 请求到来时 开始出路请求 let {pathname} = url.parse(req.url); // 获取请求来的路径 let idx = 0; let dispatch =() => { // express 需要通过next函数来迭代 if (idx === this.stack.length) return out(); // 如果路由处理不了 交给application处理 let layer = this.stack[idx++]; // 路由 、 中间件 必须要求 路径匹配才ok if (layer.match(pathname)) { // layer有可能是中间 还有可能是路由 if(!layer.route){ // 如果是中间件 直接执行 对应的方法即可 layer.handle_request(req, res, dispatch); }else{ if (layer.route.methods[req.method.toLowerCase()]){ layer.handle_request(req, res, dispatch); }else{ dispatch(); } } }else{ dispatch(); } } dispatch();}module.exports = Router;
const http = require('http');const url = require('url');const path = require('path');const Router = require('./router');const methods = require('methods');function Application() { // 路由的配置 应该归属 应用来管理}Application.prototype.lazy_route = function () { if(!this._router){ // 把应用和路由分离 this._router = new Router(); // 默认一调用express() }}Application.prototype.use = function (path,handler) { this.lazy_route(); this._router.use(path, handler)}// get post deletemethods.forEach(method=>{ Application.prototype[method] = function (path, ...handlers) { this.lazy_route(); this._router[method](path, handlers) }})Application.prototype.listen = function () { let server = http.createServer( (req, res) => { // 获取请求的方法 // 应用提供一个找不到的方法 如果路由内部无法匹配 调用此方法即可 function done(){ res.end(`Cannot ${req.method} ${req.url}`) } this.lazy_route(); this._router.handle(req,res,done) }); server.listen(...arguments)}module.exports = Application;
// 每次存储时一个对象function Layer(path,handler){ this.path = path; this.handler = handler;}Layer.prototype.match = function (pathname) { // /a/b if (this.path === pathname){ return true } // 如果是中间件 要特殊处理 if(!this.route){ // 说明是中间件 if(this.path === '/'){ return true; } return pathname.startsWith(this.path+'/') }}Layer.prototype.handle_request = function (req,res,next) { this.handler(req,res,next);}module.exports = Layer;
// 每个层 都有一个route属性const Layer = require('./layer');const methods = require('methods');function Route(){ this.stack = []; // 用于 匹配路径的时候 加速匹配,如果没有此方法的处理 直接跳过即可 this.methods = {}; // 他表示当前route中有哪些方法 {get:true,post:true}}Route.prototype.dispatch = function (req,res,out) { let idx = 0; let method = req.method.toLowerCase(); // 获取请求的方法 let dispatch = ()=>{ console.log('inner') if (idx === this.stack.length) return out(); let layer = this.stack[idx++]; if (layer.method === method){ // 获取内部的第一层 看下是否方法匹配 layer.handle_request(req, res, dispatch) }else{ dispatch(); } } dispatch();}methods.forEach(method => { Route.prototype[method] = function (handlers) { handlers.forEach(handler => { let layer = new Layer('/', handler); layer.method = method; // 用户调用什么方法 存入method就是什么 this.methods[method] = true; // 如果用户绑定方法 我就记录一下 this.stack.push(layer); }); }});module.exports = Route;