// 中间件的概念 控制是否向下执行 (权限处理)
// 中间件 可以扩展 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 delete
methods.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;