express源码简记(一)

2020-08-19  本文已影响0人  陌客百里

【序】该文主要是对源码解读过程中遇到的细节困惑进行记录的地方,并且给出解惑的答案,源码解读可以通过连接去查看。

问题一

function createApplication() {
  return {};
}

exports = module.exports = createApplication;

问题二

  1. 在全局设置一个route数组
var router = [{
    path: '*',
    method: '*',
    handle: function(req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('404');
    }
}];
  1. 修改listen函数,将http请求拦截逻辑改为匹配router路由表,如果匹配成功,执行对应的handle函数,否则执行router[0].handle函数。
listen: function(port, cb) {
    var server = http.createServer(function(req, res) {
        
        for(var i=1,len=router.length; i<len; i++) {
            if((req.url === router[i].path || router[i].path === '*') &&
                (req.method === router[i].method || router[i].method === '*')) {
                return router[i].handle && router[i].handle(req, res);
            }
        }

        return router[0].handle && router[0].handle(req, res);
    });

    return server.listen.apply(server, arguments);
}
  1. 实现get路由请求非常简单,该函数主要是添加get请求路由,只需要将其信息加入到router数组即可
get: function(path, fn) {
    router.push({
        path: path,
        method: 'GET',
        handle: fn
    });
}

问题三

  1. 引入layer类来区分同一路径下的方法
function Layer(path, fn) {
    this.handle = fn;
    this.name = fn.name || '<anonymous>';
    this.path = path;
}


//简单处理
Layer.prototype.handle_request = function (req, res) {
  var fn = this.handle;

  if(fn) {
      fn(req, res);
  }
};


//简单匹配
Layer.prototype.match = function (path) {
    if(path === this.path || path === '*') {
        return true;
    }
    
    return false;
};
  1. 将router.stack中的普通对象替换为Layer实例,这样方便在遍历处理router的item时能够让Layer进行识别和执行
var Router = function() {
    this.stack = [new Layer('*', function(req, res) {
        res.writeHead(200, {
            'Content-Type': 'text/plain'
        });
        res.end('404');        
    })];
};


Router.prototype.handle = function(req, res) {
    var self = this;

    for(var i=1,len=self.stack.length; i<len; i++) {
        if(self.stack[i].match(req.url)) {
            return self.stack[i].handle_request(req, res);
        }
    }

    return self.stack[0].handle_request(req, res);
};


Router.prototype.get = function(path, fn) {
    this.stack.push(new Layer(path, fn));
};

问题四

问题三的方法只能够将同一path匹配执行,接下来还需要匹配method方法

  1. 创建Route类
var Route = function(path) {
    this.path = path;
    this.stack = [];

    this.methods = {};
};

Route.prototype._handles_method = function(method) {
    var name = method.toLowerCase();
    return Boolean(this.methods[name]);
};

Route.prototype.get = function(fn) {
    var layer = new Layer('/', fn);
    layer.method = 'get';

    this.methods['get'] = true;
    this.stack.push(layer);

    return this;
};

Route.prototype.dispatch = function(req, res) {
    var self = this,
        method = req.method.toLowerCase();

    for(var i=0,len=self.stack.length; i<len; i++) {
        if(method === self.stack[i].method) {
            return self.stack[i].handle_request(req, res);
        }
    }
};
  1. 将Route类整合到Router中
Router.prototype.handle = function(req, res) {
    var self = this,
        method = req.method;

    for(var i=0,len=self.stack.length; i<len; i++) {
        if(self.stack[i].match(req.url) && 
            self.stack[i].route && self.stack[i].route._handles_method(method)) {
            return self.stack[i].handle_request(req, res);
        }
    }

    return self.stack[0].handle_request(req, res);
};


Router.prototype.route = function route(path) {
    var route = new Route(path);

    var layer = new Layer(path, function(req, res) {
        route.dispatch(req, res);
    });

    layer.route = route;

    this.stack.push(layer);
    
    return route;
};


Router.prototype.get = function(path, fn) {
    var route = this.route(path);
    route.get(fn);

    return this;
};
上一篇 下一篇

猜你喜欢

热点阅读