Next in Express

906 阅读1分钟

1. next的作用

在定义express中间件函数的时候,第三个参数就是next,next()负责将控制权交给下一个中间件,如果当前中间件没有终结请求,并且next没有被调用,那么请求将被挂起,后边定义的中间件将得不到被执行的机会。

2. 何时使用next

Next主要保证中间件的顺序执行,按理说我们应该在所用中间件中调用next,但是有一个例外,如果我们定义的中间件终止了本次请求,那么就不应该再调用next函数,否则会报错

next源码解析

在expree框架中,中间件和路由都会抽象成layer对象,而且在express中有两个next,一个是中间件的next,一个是路由中的next,通过源码来看一下这两个有什么区别。

//非路由中间件
	function next(err){
    	var layerError = err === 'route'?null:err
        
        // signal to exit router,
        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 (match !== true && idx < stack.length) {
            layer = stack[idx++];
            match = matchLayer(layer, path);
            route = layer.route;

            if (typeof match !== 'boolean') {
              // hold on to layerError
              layerError = layerError || match;
            }

            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;
            }
    	}
    }

next内部有一个while循环,每次循环都会从stack中拿出一个layer,这个layer中包含了路由和中间件信息,然后就会用layer和请求的path就行匹配,如果匹配成功就会执行layer.handle_request,调用中间件函数。但如果匹配失败,就会循环下一个layer(即中间件)。

注意:app.use注册的中间件,如果path参数为空,则默认为"/",而path为"/"的中间件默认匹配所有的请求。

路由中间件

function next(err) {
    if (err && err === 'route') {
      return done();
    }

    var layer = stack[idx++];
    if (!layer) {
      return done(err);
    }

    if (layer.method && layer.method !== method) {
      return next(err);
    }

    if (err) {
      layer.handle_error(err, req, res, next);
    } else {
      layer.handle_request(req, res, next);
    }
  }

这个next负责同一个路由的多个中间件的控制权的传递,并且它会接收一个参数"route",如果调用next(“route”),则会跳过当前路由的其它中间件,直接将控制权交给下一个路由。

转自 cnodejs.org/topic/5757e…