为什么我的中间件执行两次?
我在express.js / node.js中编写了一个中间件,用于检查会话,以及是否find用户ID,显示用户的菜单,或者显示默认菜单。
每个页面请求检查一个id并从数据库中提取用户数据(id,name,category等)
这里是中间件:
module.exports = function(req,res,next){ console.log("INSIDE SESSION HANDLER"); if(!req.session.uid) return next(); else{ User.get(uid, function(user){ if (!user) {return next(err);} else{ req.user = res.locals.user = user; next(); } }) } }
然后,ejs检查当地人,如果有一个ID,显示用户的菜单。
我正在加载一个testing页面,我没有使用socket.io库,但忘记删除<script src="/socket.io/socket.io.js"></script>
行。
<!DOCTYPE html> <html> <head> <title><%= title %> , <%= settings.title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> <script src="/socket.io/socket.io.js"></script>//<== SHOULD DELETE THIS <h1>Login</h1> <%include menu%> //<== USES EJS TO CHECK LOCALS AND SHOW DEFAULT OR USER MENU </head> <body>
当script src
行不在那里时,中间件只执行一次(看到console.log("INSIDE SESSION HANDLER");
只有一次)。
当script src
行在那里时,显然是给了一个404错误,但中间件执行了两次(看到console.log("INSIDE SESSION HANDLER");
两次)。
这是console.log
的输出:
INSIDE SESSION HANDLER GET / 304 66ms //page GET /stylesheets/style.css 304 11ms INSIDE SESSION HANDLER //again GET /socket.io/socket.io.js 404 28ms - 1.04kb GET /multimedia/01.jpg 304 4ms //images... GET /multimedia/02.jpg 304 5ms
我想真正理解请求/响应和中间件。 那么为什么会这样呢? 为什么中间件因为404错误而执行了两次? 404错误响应是否会导致中间件执行两次?
谢谢
编辑
我在app.js中使用中间件,如下所示:
app.use(favicon(__dirname + '/node_modules/static-favicon/favicon.ico')); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(session({resave:'false', saveUninitialized:'false', secret:'secret'})); app.use(express.static(path.join(__dirname, 'public'))); app.set('multimedia', __dirname + '/public/multimedia'); app.use(handler); //<= THE MIDDLEWARE IN QUESTION app.use(messages); app.get('/', routes.list); app.get('/register', register.form); app.post('/register', register.submitit);
中间件运行两次的原因是它正在为初始请求运行一次,为404(不存在的静态脚本)运行一次。
如果express.static
可以find一个文件,它会发送响应给相应的文件,如果找不到正确的文件(就像你的情况一样),它会调用next()
来尝试将请求匹配到其他路由,运行下面定义的任何其他中间件express.static
。
换句话说,如果express.static
确实find要提交的文件,那么它下面的中间件将不会运行。 在你的情况下,中间件运行一次实际的请求,一旦试图find文件或正确的路线作为回应。
这可以通过logging正常静态文件的req.path
和不存在的文件来观察:
app.js –
app.use(express.static(path.join(__dirname, 'public'))); app.use(function(req, res, next){ console.log('Requested path: %s', req.path); next(); })
layout.hbs(呈现'/') –
<!DOCTYPE html> <html> <head> <title>{{title}}</title> <link rel='stylesheet' href='/stylesheets/style.css' /> <!-- exists --> <link rel='stylesheet' href='/stylesheets/foo.css' /> <!-- doesn't exist --> </head> <body> {{{body}}} </body> </html>
我们将看到中间件只会logging初始请求和404的请求path,而不是静态文件。 例如:
Requested path: / Requested path: /stylesheets/foo.css
希望这可以帮助。
你在哪里申请这个中间件?
例如,如果你有
app.use(handler)
其中handler
的formsfunction (req, res, next)
,它将应用于每个请求(使用任何HTTP动词)。 或者,
app.get('/some/route', handler)
handler
将适用于/some/route
(eg /some/route/any/deepness
)之下的/some/route/any/deepness
。
所以我的猜测是,你正在使用中间件function (我正在交换处理程序和中间件 ,它们具有相同的函数签名 – 也许处理程序更适合于向那些调用next()
人发送响应和中间件的函数)。 但是如果没有这个中间件如何应用的背景很难说。
请参阅编写中间件和Express提供的其他指南。
PS。 你不需要在中间件中return next()
。 就next()
。