从技术角度而言,你在 Sails 应用程序中编写的许多代码都是中间件,因为它们运行在传入请求和传出响应之间,也就是说,它们运行在请求/响应堆栈的“中间”。在 MVC 框架中,术语“中间件”通常更具体地指的是在你的路由处理代码(即你的 控制器操作)之前或之后运行的代码,这使得能够将同一段代码应用于多个路由或操作。Sails 对中间件设计模式提供了强大的支持。根据你的需要,你可以选择实现
routes
特性的钩子——在某个或多个路由处理程序之前应用代码Sails 与 Express / Connect 中间件完全兼容,它们是接受req
、res
和next
作为参数的函数。每个应用程序都使用可配置的中间件堆栈来处理 HTTP 请求。应用程序每次接收到一个 HTTP 请求时,其配置的 HTTP 中间件堆栈都会按顺序运行。
请注意,此 HTTP 中间件堆栈仅用于“真实”HTTP 请求;它会忽略虚拟请求(例如来自实时 Socket.io 连接的请求)。
默认情况下,Sails 使用一些不同的中间件函数来处理低级别的 HTTP 相关任务。这些任务包括解释 Cookie、解析 HTTP 请求主体、提供资源,甚至附加应用程序的路由。你可以 在此处详细了解默认中间件堆栈。
由于中间件堆栈提供了合理的默认值,许多 Sails 应用程序根本不需要修改此配置。但对于需要更多灵活性的情况,Sails 使得添加、重新排序、覆盖和禁用应用程序 HTTP 中间件堆栈中的函数变得十分简单。
要配置新的自定义 HTTP 中间件函数,请在middleware
(例如“foobar”)中添加一个中间件函数作为新的键,然后在middleware.order
数组中添加其键的名称(“foobar”),你希望它在中间件链中运行的任何位置。
除了“order”(用于配置中间件堆栈的顺序)之外,分配给sails.config.middleware
的任何键的值都应该是一个接受三个参数的函数:req
、res
和next
。此函数的工作方式几乎与 策略完全相同,唯一明显的区别是它的执行时间。
如果需要为自定义中间件函数运行一些一次性设置代码,则需要在传入它之前执行这些代码。建议的做法是使用自调用(即 “立即调用”)包装函数。在下面的示例中,请注意,不是直接将值设置为“req、res、next”函数,而是使用自调用函数来“包装”一些初始设置代码。然后,该自调用包装函数返回最终的中间件(req、res、next)函数,因此它以与直接传入时相同的方式设置在键上。
以下示例显示了如何设置三个不同的自定义 HTTP 中间件函数
// config/http.js
module.exports.http = {
middleware: {
order: [
'cookieParser',
'session',
'passportInit', // <==== If you're using "passport", you'll want to have its two
'passportSession', // <==== middleware functions run after "session".
'bodyParser',
'compress',
'foobar', // <==== We can put other, custom HTTP middleware like this wherever we want.
'poweredBy',
'router',
'www',
'favicon',
],
// An example of a custom HTTP middleware function:
foobar: (function (){
console.log('Initializing `foobar` (HTTP middleware)...');
return function (req,res,next) {
console.log('Received HTTP request: '+req.method+' '+req.path);
return next();
};
})(),
// An example of a couple of 3rd-party HTTP middleware functions:
// (notice that this time we're using an existing middleware library from npm)
passportInit : (function (){
var passport = require('passport');
var reqResNextFn = passport.initialize();
return reqResNextFn;
})(),
passportSession : (function (){
var passport = require('passport');
var reqResNextFn = passport.session();
return reqResNextFn;
})()
},
}
你还可以使用上面描述的策略来覆盖内置中间件,例如主体解析器(请参见 自定义主体解析器)。
虽然不推荐这样做,但你甚至可以完全禁用内置 HTTP 中间件函数——只需将其从
middleware.order
数组中删除即可。这提供了完全的灵活性,但应谨慎使用。如果你选择禁用内置 HTTP 中间件,请确保完全了解其后果。禁用内置 HTTP 中间件可能会显著改变应用程序的工作方式。
Sails 应用程序的一大优势是,它们可以利用大量现有的 Express/Connect 中间件,但人们在实际尝试这样做时,会经常遇到一个常见的问题
“我应该在哪里
app.use()
此内容?”.
在大多数情况下,答案是在 sails.config.http.middleware
中将 Express 中间件安装为自定义 HTTP 中间件。这将为你的 Sails 应用程序的所有 HTTP 请求触发它,并允许你配置它相对于其他 HTTP 中间件的运行顺序。
你永远不应该覆盖或删除
router
HTTP 中间件。它是 Sails 的内置组件;没有它,应用程序的显式路由和蓝图路由将无法正常工作。
要使 Express 中间件仅应用于某个特定的操作,你还可以将 Express 中间件包含为策略——只需确保你确实希望它在 HTTP 和虚拟套接字请求中都运行即可。
要执行此操作,请编辑 config/policies.js
以在实际的包装策略中要求和设置中间件(通常是一个好主意),或者在你的 policies.js 文件中直接要求它。以下示例出于简洁性考虑,采用了后一种策略
var auth = require('http-auth');
var basic = auth.basic({
realm: 'admin area'
}, function (username, password, onwards) {
return onwards(username === 'Tina' && password === 'Bullock');
});
//...
module.exports.policies = {
'*': [true],
// Prevent end users from doing CRUD operations on products reserved for admins
// (uses HTTP basic auth)
'product/*': [auth.connect(basic)],
// Everyone can view product pages
'product/show': [true]
}