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

时间:2011-09-07 16:48:43

标签: node.js express

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

9 个答案:

答案 0 :(得分:100)

middleware

我在新项目中分离中间件的概念已经过了一半。

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

// express
var app = express();
// middleware
var stack = middleware();

然后,您可以通过调用.use

将层添加到中间件堆栈
// express
app.use(express.static(..));
// middleware
stack.use(function(data, next) {
  next();
});

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

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

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

// express, you need to do nothing
// middleware
stack.handle(someData);

更完整的例子:

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

在明确的术语中,您只需为每个传入的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); 
});

答案 1 :(得分:55)

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

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

答案 2 :(得分:27)

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

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

您可以使用app.use方法获得流like this

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');

但您也可以使用其他方法并将每个中间件作为函数参数传递。这是example from the MooTools Nodejs website,其中midleware在response被发送回客户端之前获取Twitter,Github和Blog流。注意函数如何作为app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){中的参数传递。仅对GET请求调用app.get,将为所有请求调用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
    });
});

答案 3 :(得分:13)

expressjs guide对你的问题有很好的答案,我强烈建议你阅读一下,我发布了一个简短的指南片段,指南非常好。

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

概述

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

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

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

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

enter image description here

示例

这是一个简单的“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)   

中间件功能myLogger

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

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

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

要加载中间件功能,请调用 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)

每次应用收到请求时,都会向终端显示消息“LOGGED”。

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

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

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

<小时/>

  1. 此帖子仅包含myLogger中间件,如需进一步发布,您可以转到原始的expressjs指南here

答案 4 :(得分:7)

=====非常简单的解释=====

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

简单中间件示例:

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

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

几个中间件陷阱:

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

答案 5 :(得分:6)

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

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

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

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

答案 6 :(得分:5)

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

中间件链总是按照其定义的确切顺序进行调用,因此确切了解特定的中间件正在做什么是至关重要的。
一旦中间件功能完成,它就会调用下一个函数在链中通过调用其下一个参数作为函数。
完成链完成后,将调用用户请求处理程序。

答案 7 :(得分:1)

保持简单,伙计!

注意:答案与ExpressJS内置的middlware案例有关,但中间件有不同的定义和用例。

从我的角度来看,中间件充当实用程序或辅助函数,但它的激活和使用是完全可选的,使用app.use('path', /* define or use builtin middleware */),我们不希望我们编写一些代码用于执行客户端的每个HTTP请求所需的非常常见的任务,如处理cookie,CSRF令牌和...,这在大多数应用程序中非常常见所以中间件可以帮助我们为我们的每个HTTP请求执行所有操作某个堆栈,序列或操作顺序中的客户端然后将该过程的结果作为单个客户端请求单元提供

示例:

根据客户的要求接受客户请求并向他们提供回复是Web服务器技术的本质。

想象一下,如果我们提供的响应只是“你好,世界!”对我们网站服务器的根URI的GET HTTP请求的文本是非常简单的场景,不需要任何其他内容,但是如果我们检查当前登录的用户然后以“Hello,Username!”进行响应。在这种情况下,我们需要一个中间件来处理所有客户端请求元数据并向我们提供从客户端请求中获取的标识信息,然后根据该信息我们可以唯一地识别我们当前的用户并且可以回复他/她有一些相关的数据。

希望它可以帮助别人!

答案 8 :(得分:0)

如果我想这样解释的话,我可以从traversymedia youtube频道速成课程中学习。
好的,所以中间件是一个函数,它是在您这样调用路由后执行的。

var logger = function(req, res, next){
   console.log('logging...');
   next();
}

app.use(logger);

此记录器功能在您每次刷新页面时执行,这意味着您可以在页面呈现任何操作api调用后基本编写任何内容,然后您可以在其中编写任何内容。并将此中间件放在您的中间件路由功能顺序之前非常重要或不起作用