0

0

0

修罗

站点介绍

只有了解事实才能获得真正的自由

express源码阅读(二)请求、中间件

修罗 2022-07-16 2078 0条评论 nodejs

首页 / 正文

express源码阅读(二)请求、中间件

一. express官方例子

var express = require("../../index");
var app = express();

app.get("/", function (req, res) {
  res.send("Hello World");
});

app.listen(3000, function () {
  console.log("Express started on port 3000");
});

分析:

app.listen做了什么?

访问/如何匹配到回调的?

二、listen

listen方法来自application.js的混入

1、express.js

混入对象到express导出的函数

1638629868461.png

2、application.js

混入的listen方法

1638629783865.png

2.1 createServer

this即app函数,因为是app调用的,所以执行环境为app对象。此为this隐式绑定。

  • listen函数调用
app.listen(3000, function () {
  console.log("Express started on port 3000");
});
  • listen函数执行
var server = http.createServer(function (req, res, next) {
   app.handle(req, res, next);
};);
return server.listen([3000, function () {
   console.log("Express started on port 3000");
}])

代码执行用node的http核心模块创建服务器,监听3000端口;浏览器请求后会执行到app.handle方法,将request、response对象传递给此方法,next此时为undefined。

三、浏览器请求/

3.1 app.handle

handle方法将挂载到app中的router取出,调用router中的handle继续处理请求。

1638688121690.png

3.2 router中的handle

此方法即匹配请求真正地方,一个请求即一个中间件,根据请求路径调用next匹配中间件,最后执行中间件,再次调用next匹配下一个中间件。

1638688980022.png

3.2.1 handle主要内容

proto.handle = function handle(req, res, out) {
  var self = this;
  var idx = 0;
  // middleware and routes
  var stack = self.stack;
  next();

  function next(err) {
    // next("route")可以传这样传参数否则异常
    var layerError = err === "route" ? null : err;

    // 传参数router异常,传其他的(除route)下面代码有体现
    if (layerError === "router") {
      setImmediate(done, null);
      return;
    }

    // no more matching layers
    if (idx >= stack.length) {
      setImmediate(done, layerError);
      return;
    }

    // get pathname of request
    var path = getPathname(req);

    if (path == null) {
      return done(layerError);
    }

    // find next matching layer
    var layer;
    var match;
    var route;

    // while匹配start
    while (match !== true && idx < stack.length) {
      layer = stack[idx++];
      // use的中间件过来匹配为true,循环跳出,调next才会再执行找下一个匹配
      match = matchLayer(layer, path);
      route = layer.route;

      if (match !== true) {
        continue;
      }

      if (!route) {
        // process non-route handlers normally
        continue;
      }

      if (layerError) {
        // routes do not match with a pending error
        match = false;
        continue;
      }

      var method = req.method;
      // 请求方法匹配
      var has_method = route._handles_method(method);

      // build up automatic options response
      if (!has_method && method === "OPTIONS") {
        appendMethods(options, route._options());
      }

      // don't even bother matching route
      if (!has_method && method !== "HEAD") {
        match = false;
        continue;
      }
    }
    // while匹配end

    // no match
    if (match !== true) {
      return done(layerError);
    }

    // store route for dispatch on change
    if (route) {
      req.route = route;
    }


    var layerPath = layer.path;

    // 中间件匹配完成调用
    self.process_params(layer, paramcalled, req, res, function (err) {
      if (err) {
        return next(layerError || err);
      }
      // 非全局中间件
      if (route) {
        return layer.handle_request(req, res, next);
      }

      // 全局中间件没有route
      trim_prefix(layer, layerError, layerPath, path);
    });
  }

全局中间件通过layer.keys匹配router.params

proto.process_params = function process_params(layer, called, req, res, done) {
    // this即router
    var params = this.params;
    var keys = layer.keys;

  // fast track
  if (!keys || keys.length === 0) {
    return done();
  }
  ...
}

router

function router(req, res, next) {}
router.params = {};

3.2.2 layer.handle_request

Layer.prototype.handle_request = function handle(req, res, next) {
  var fn = this.handle;

  if (fn.length > 3) {
    // not a standard request handler
    return next();
  }

  try {
    fn(req, res, next);
  } catch (err) {
    next(err);
  }
};

3.2.3 trim_prefix

内部核心代码

function trim_prefix(layer, layerError, layerPath, path) {
  ...
  // 执行layer内部的中间件函数
  if (layerError) {
    layer.handle_error(layerError, req, res, next);
  } else {
    layer.handle_request(req, res, next);
  }
}

评论(0)


最新评论

  • https://www.studyglobus.com/author/carroll34a5552/

    Ценники на вывоз мусора сейчас космос, любые лайфхаки по экономии в тему.

  • Richardgrold

    1xbet onlayn kazino platforması ilə vaxtınızı daha səmərəli və maraqlı keçirin. Saytın canlı kazino bölməsi istifadəçilərə fərqli bir dünya təklif edir. Burada canlı dilerli kazino oyunlarının hər bir növünü sınaqdan keçirə bilərsiniz. Krupyelərin peşəkarlığı oyunun dinamikasını və marağını artırır. Müntəzəm olaraq yenilənən oyun siyahısı cansıxıcılığa yol vermir. Hesabınızı artırmaq üçün onlarla fərqli və etibarlı üsul mövcuddur. Qazanılan pullar cəmi bir neçə dəqiqə ərzində şəxsi hesabınıza köçürülür. Aktiv fəaliyyətinizə görə fərdi bonuslar və hədiyyələr qazana bilərsiniz. Dəstək xidməti həm çat, həm də e-poçt vasitəsilə kömək göstərir. 1xbet ailəsinə qoşulun və böyük uduşlar üçün ilk addımı atın. onlayn kazino

  • 砂岩白丘

    我一直梦想, 看到你们相册那样的地方。真棒。

  • 城市地標

    我喜欢, 这里分享真实经验。你的项目 就是 属于这里的。请继续。

  • 宗教地標

    我热爱这样的想法, 去那么多国家。真的很鼓舞。

  • 觀景高地

    能感受到热爱。继续保持 感受。

  • 最佳季節

    我关注这样的资源, 写得很实在。你的网站 就是 属于这里的。加油。

  • 1

    1

  • 1

    1

  • -1' OR 2+158-158-1=0+0+0+1 or 'TKCTZnRa'='

    1

日历

2026年07月

   1234
567891011
12131415161718
19202122232425
262728293031 

文章目录

推荐关键字: Linux webpack js 算法 MongoDB laravel JAVA jquery javase redis