中间件和app.use在Expressjs中实际意味着什么?

iZ.*_*iZ. 216 node.js express

我看到的几乎每个Express应用程序都有一个app.use中间件声明,但我没有找到一个清晰,简洁的解释,说明中间件实际上是什么以及app.use声明正在做什么.即便是快递文件本身也有点模糊.你能帮我解释一下这些概念吗?

Ray*_*nos 104

中间件

我正在将新项目中间件的概念分离出来.

中间件允许您定义应该流经的一系列操作.Express服务器本身就是一堆中间件.

// express
var app = express();
// middleware
var stack = middleware();
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过调用将层添加到中间件堆栈 .use

// express
app.use(express.static(..));
// middleware
stack.use(function(data, next) {
  next();
});
Run Code Online (Sandbox Code Playgroud)

中间件堆栈中的一个层是一个函数,它接受n个参数(2表示快速,req&res)和一个next函数.

中间件期望该层进行一些计算,扩充参数然后调用next.

除非您处理它,否则堆栈不会执行任何操作.每次在服务器上捕获传入的HTTP请求时,Express都将处理堆栈.使用中间件,您可以手动处理堆栈.

// express, you need to do nothing
// middleware
stack.handle(someData);
Run Code Online (Sandbox Code Playgroud)

一个更完整的例子:

var middleware = require("../src/middleware.js");

var stack = middleware(function(data, next) {
    data.foo = data.data*2;
    next();
}, function(data, next) {
    setTimeout(function() {
        data.async = true;
        next();
    }, 100)
}, function(data) {
    console.log(data);
});

stack.handle({
    "data": 42
})
Run Code Online (Sandbox Code Playgroud)

在明确的术语中,您只需为每个传入的HTTP请求定义一组您希望表达的操作.

在快速(而不是连接)方面,您拥有全局中间件和路由特定的中间件.这意味着您可以将中间件堆栈附加到每个传入的HTTP请求,或仅将其附加到与特定路由交互的HTTP请求.

快递和中间件的高级示例:

// middleware 

var stack = middleware(function(req, res, next) {
    users.getAll(function(err, users) {
        if (err) next(err);
        req.users = users;
        next();  
    });
}, function(req, res, next) {
    posts.getAll(function(err, posts) {
        if (err) next(err);
        req.posts = posts;
        next();
    })
}, function(req, res, next) {
    req.posts.forEach(function(post) {
        post.user = req.users[post.userId];
    });

    res.render("blog/posts", {
        "posts": req.posts
    });
});

var app = express.createServer();

app.get("/posts", function(req, res) {
   stack.handle(req, res); 
});

// express

var app = express.createServer();

app.get("/posts", [
    function(req, res, next) {
        users.getAll(function(err, users) {
            if (err) next(err);
            req.users = users;
            next();  
        });
    }, function(req, res, next) {
        posts.getAll(function(err, posts) {
            if (err) next(err);
            req.posts = posts;
            next();
        })
    }, function(req, res, next) {
        req.posts.forEach(function(post) {
            post.user = req.users[post.userId];
        });

        res.render("blog/posts", {
            "posts": req.posts
        });
    }
], function(req, res) {
   stack.handle(req, res); 
});
Run Code Online (Sandbox Code Playgroud)

  • @iZ使用它将它添加到堆栈中.然后每个请求都通过堆栈. (9认同)
  • @Raynos,你的项目的链接,"中间件",已被打破. (7认同)
  • 凉.我仍然对`app.use()`语法感到困惑.中间件的实际返回值是什么,以及`use`用它做什么? (5认同)
  • 嗯......在这种情况下,中间件是你自己的库还是快递的一部分? (4认同)
  • 链接已经死了 (3认同)

Bar*_*Rho 58

在简化事物之后,可以将Web服务器视为接收请求并输出响应的函数.因此,如果您将Web服务器视为一个函数,您可以将它组织成几个部分并将它们分成更小的函数,以便它们的组合将是原始函数.

中间件是您可以与其他人合并的较小功能,显而易见的好处是您可以重复使用它们.


Ser*_*gio 30

我添加一个迟到的答案来添加以前答案中未提及的内容.

到目前为止,应该清楚中间件是在客户端请求服务器应答之间运行的功能.所需的最常见的中间件功能是错误管理,数据库交互,从静态文件或其他资源获取信息.要移动中间件堆栈,必须调用下一个回调,您可以在中间件函数的末尾看到它以移动到流程的下一步.

您可以使用app.use方法,并有一个流程是这样:

var express = require('express'),
    app = express.createServer(),                                                                                                                                                 
    port = 1337;

function middleHandler(req, res, next) {
    console.log("execute middle ware");
    next();
}

app.use(function (req, res, next) {
    console.log("first middle ware");                                                                                                             
    next();
});

app.use(function (req, res, next) {
    console.log("second middle ware");                                                                                                             
    next();
});

app.get('/', middleHandler, function (req, res) {
    console.log("end middleware function");
    res.send("page render finished");
});

app.listen(port);
console.log('start server');
Run Code Online (Sandbox Code Playgroud)

但您也可以使用其他方法并将每个中间件作为函数参数传递.以下是MooTools Nodejs网站的一个示例,其中midleware在response发送回客户端之前获取Twitter,Github和Blog流.注意函数如何作为参数传递app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){.app.get只会为GET请求调用using ,app.use将为所有请求调用.

// github, twitter & blog feeds
var githubEvents = require('./middleware/githubEvents')({
    org: 'mootools'
});
var twitter = require('./middleware/twitter')();
var blogData = require('./blog/data');
function getLatestBlog(req, res, next){
    blogData.get(function(err, blog) {
        if (err) next(err);
        res.locals.lastBlogPost = blog.posts[0];
        next();
    });
}

// home
app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){
    res.render('index', {
        title: 'MooTools',
        site: 'mootools',
        lastBlogPost: res.locals.lastBlogPost,
        tweetFeed: res.locals.twitter
    });
});
Run Code Online (Sandbox Code Playgroud)

  • 我正在寻找一个答案****Express.js是否支持基于路由(基于路由器)的中间件安装?**看来你已经在答案中显示了它. (2认同)
  • 嗨@ TannerSummers,`.get()`方法有3种类型的参数:第一种,最后一种和中间种.在内部,它检测是否有多于2的参数,并使用那些(中间的)作为中间件函数,从左到右调用它们. (2认同)

Sur*_*ain 17

expressjs 指南对你的问题有相当简洁的答案,我强烈建议你阅读,我发布了一个简短的指南片段,指南相当不错.

编写用于Express应用程序的中间件

概观

中间件函数是可以访问请求对象( req),响应对象( res)以及应用程序的请求 - 响应周期中的下一个函数的函数.下一个功能是Express路由器中的一个功能,当被调用时,它会在当前中间件之后执行中间件.

中间件功能可以执行以下任务:

  • 执行任何代码.
  • 更改请求和响应对象.
  • 结束请求 - 响应周期.
  • 调用堆栈中的下一个中间件.

如果当前的中间件函数没有结束请求 - 响应周期,则必须调用next()将控制权传递给下一个中间件函数.否则,请求将被挂起.

在此输入图像描述

这是一个简单的"Hello World"Express应用程序的示例.本文的其余部分将定义并向应用程序添加两个中间件函数:一个名为myLogger,用于打印简单的日志消息,另一个名为requestTime 1,用于显示HTTP请求的时间戳.

var express = require('express')
var app = express()

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)   
Run Code Online (Sandbox Code Playgroud)

中间件功能myLogger

这是一个名为"myLogger"的中间件函数的简单示例.当对应用程序的请求通过时,此函数只打印"LOGGED".中间件函数被分配给名为myLogger的变量.

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}
Run Code Online (Sandbox Code Playgroud)

注意上面的调用next().调用此函数会调用应用程序中的下一个中间件函数.在接下来的()函数不是Node.js的或快递API的一部分,但传递给中间件功能的第三个参数.在接下来的()函数可以被命名为任何东西,但是按照惯例,它总是被命名为"下一个".为避免混淆,请始终使用此约定.

要加载中间件函数,请调用app.use(),指定中间件函数.例如,以下代码在到根路径(/)的路由之前加载myLogger中间件函数.

var express = require('express')
var app = express()

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

app.use(myLogger)

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)
Run Code Online (Sandbox Code Playgroud)

每次应用程序收到请求时,它都会向终端输出消息"LOGGED".

中间件加载的顺序很重要:首先加载的中间件函数也会先执行.

如果myLogger在到达根路径的路径之后加载,则请求永远不会到达,并且应用程序不会打印"LOGGED",因为根路径的路由处理程序会终止请求 - 响应周期.

中间件函数myLogger只是打印一条消息,然后通过调用next()函数将请求传递给堆栈中的下一个中间件函数.


  1. 这篇文章只包含myLogger中间件,如需进一步的帖子,你可以在这里找到原始的expressjs指南.

  • 好一个.这是我在这里看到的最明确的解释,是的,很奇怪,没有人引用它! (2认同)

小智 9

=====很简单的解释=====

中间件通常在Express.js框架的上下文中使用,并且是node.js的基本概念.简而言之,它基本上是一个可以访问应用程序的请求和响应对象的函数.我想要考虑的方式是一系列"检查/预筛选",请求在应用程序处理之前经过.例如,中间件很适合确定请求在进入应用程序之前是否经过身份验证,如果请求未经过身份验证则返回登录页面,或者用于记录每个请求.许多第三方中间件可用于实现各种功能.

简单中间件示例:

var app = express();
app.use(function(req,res,next)){
    console.log("Request URL - "req.url);
    next();
}
Run Code Online (Sandbox Code Playgroud)

上面的代码将针对每个请求执行并记录请求url,next()方法基本上允许程序继续.如果未调用next()函数,则程序将不会继续进行并且将在执行中间件时停止.

几个中间件陷阱:

  1. 应用程序中的中间件顺序很重要,因为请求将按顺序遍历每个中间件.
  2. 忘记在中间件函数中调用next()方法可以停止处理您的请求.
  3. 对中间件函数中的req和res对象进行任何更改都会使更改可用于使用req和res的应用程序的其他部分


naz*_*naz 7

中间件是在输入/源之后在中间执行的函数,然后产生输出,该输出可以是最终输出,或者可以由下一个中间件使用直到循环完成.

它就像一个产品通过装配线,在它移动时会被修改,直到它完成,评估或被拒绝.

中间件需要处理某些值(即参数值),并基于某些逻辑,中间件将调用或不调用下一个中间件或将响应发送回客户端.

如果您仍然无法掌握中间件概念,那么它的方式与装饰器或命令链模式类似.


ris*_*dev 5

中间件是在调用用户定义的处理程序之前由Express js路由层调用的链接函数的子集.中间件函数可以完全访问请求和响应对象,并可以修改它们中的任何一个.

中间件链始终按照其定义的确切顺序进行调用,因此确切了解特定中间件的作用至关重要.
中间件函数完成后,它会通过调用其下一个参数作为函数来调用链中的下一个函数.
完成链完成后,将调用用户请求处理程序.