我看到几乎每个 Express 应用程序都有一个中间件 app.use
语句,但我还没有找到一个清晰简洁的解释什么是中间件以及 app.use
语句实际上在做什么。即使是 express 的官方文档本身也有点模糊不清。你能为我解释一下这些概念吗?
我看到几乎每个 Express 应用程序都有一个中间件 app.use
语句,但我还没有找到一个清晰简洁的解释什么是中间件以及 app.use
语句实际上在做什么。即使是 express 的官方文档本身也有点模糊不清。你能为我解释一下这些概念吗?
我正在将中间件的概念分离到一个新项目中。
中间件允许您定义一系列应该通过的操作。Express服务器本身就是一个中间件栈。
// express
var app = express();
// middleware
var stack = middleware();
然后,您可以通过调用 .use
来向中间件栈添加层。
// express
app.use(express.static(..));
// middleware
stack.use(function(data, next) {
next();
});
中间件堆栈中的一层是一个函数,它需要n个参数(对于express来说,是req
和res
),以及一个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
})
在Express中,你可以定义一个操作堆栈,用于处理每个传入的HTTP请求。
与Connect不同,Express有全局中间件和特定路由中间件。这意味着你可以将中间件堆栈附加到每个传入的HTTP请求上,或仅将其附加到与某个路由交互的HTTP请求上。
Express和中间件的高级示例:
// 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);
});
app.use()
语法。中间件的实际返回值是什么,use
如何处理它? - iZ.简化后,一个Web服务器可以被视为一个接受请求并输出响应的函数。因此,如果您将Web服务器视为函数,则可以将其组织成几个部分,并将它们分成较小的函数,以便它们的组合将是原始函数。
中间件是您可以与其他函数组合使用的较小函数,显而易见的好处是您可以重用它们。
在此我补充一点前面回答中未提到的内容。
现在应该很清楚了,中间件是在客户端请求和服务器响应之间运行的一个或多个函数。最常见的中间件功能包括错误管理、数据库交互、从静态文件或其他资源获取信息。为了在中间件堆栈中继续向下执行,必须调用下一个回调函数,在中间件函数末尾可以看到这一点,以便在流程中移动到下一步。
您可以使用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');
但你也可以采用另一种方法,将每个中间件作为函数参数传递。以下是MooTools Nodejs网站的示例,其中中间件获取Twitter、Github和Blog流,然后将response
发送回客户端。注意,在app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){
中如何将函数作为参数传递。使用app.get
仅针对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
});
});
.get()
方法接受3种类型的参数:第一个、最后一个和中间的参数。在内部,它检测是否有超过2个参数,并使用那些(中间的)作为中间件函数,从左到右依次调用它们。 - Sergioexpressjs 指南 对你的问题有很好的回答,我强烈建议你阅读一下,我在这里发布指南的一个简短片段,该指南非常好。
中间件函数是具有访问请求对象 (req)、响应对象 (res) 和应用程序请求-响应周期中的下一个函数的功能。下一个函数是 Express 路由器中的一个函数,当调用它时,执行当前中间件后继的中间件。
中间件函数可以执行以下任务:
如果当前中间件函数不结束请求-响应周期,则必须调用next()将控制传递给下一个中间件函数。否则,请求将被挂起。
示例
下面是一个简单的“Hello World” Express应用程序示例。本文的其余部分将定义并添加两个中间件函数到应用程序中:一个名为myLogger的函数,它打印一个简单的日志消息,另一个名为requestTime1的函数,它显示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()
}
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)
=====非常简单的解释=====
中间件通常在Express.js框架的上下文中使用,并且是node.js的一个基本概念。简而言之,它基本上是一个具有对应用程序请求和响应对象访问权限的函数。我希望通过这种方式思考中间件:在请求被应用程序处理之前,请求经过一系列的“检查/预筛选”。例如,中间件可以很好地确定请求是否经过身份验证,如果请求未经过身份验证,则返回登录页面或记录每个请求。许多第三方中间件可用于实现各种功能。
简单的中间件示例:
var app = express();
app.use(function(req,res,next)){
console.log("Request URL - "req.url);
next();
}
以上的代码将会在每个请求进来时执行,并记录请求的URL,next()方法实际上允许程序继续执行。如果不调用next()函数,程序将不会继续执行,并将在中间件的执行处停止。
中间件的一些注意事项:
next()
而是 return next()
。这有什么区别吗? - KansaiRobotnext()
是因为我们希望调用下一个中间件,我认为 next()
或 return next()
不应该有任何区别!
不过这还取决于代码是什么... - Vaibhav KB保持简单,伙计!
注意:答案与ExpressJS内置中间件有关,但是中间件有不同的定义和用例。
从我的角度来看,中间件充当实用程序或辅助函数,但其激活和使用完全是可选的,通过使用app.use('path', /* define or use builtin middleware */)
,我们不需要编写一些代码来执行每个客户端HTTP请求所需的非常常见的任务,例如处理cookie、CSRF令牌等,在大多数应用程序中都很常见,因此中间件可以帮助我们在一些堆栈、序列或操作顺序中为每个客户端HTTP请求执行所有这些操作,然后将处理结果作为客户端请求的单个单位提供。
例如:
接受客户端请求并根据他们的请求提供回复是Web服务器技术的本质。
假设我们对Web服务器的根URI发出GET HTTP请求,只需要"Hello, world!"文本作为响应,这是一个非常简单的情况,不需要任何其他东西。但是,如果我们要检查当前登录的用户,然后用"Hello, 用户名!"来响应,就需要更多的东西了。在这种情况下,我们需要一个中间件来处理所有客户端请求元数据,并提供从客户端请求获取的标识信息,然后根据该信息唯一地识别我们当前的用户,可以向他/她响应一些相关数据。var logger = function(req, res, next){
console.log('logging...');
next();
}
app.use(logger);
这个日志记录器函数每次刷新页面时都会执行,这意味着您可以在其中编写任何您需要在页面渲染后执行的操作,例如任何操作API调用、重置事项等。并且将此中间件放置在路由函数之前非常重要,中间件的顺序非常重要,否则它将无法正常工作。