为什么我的中间件执行了两次?

时间:2016-01-18 19:58:07

标签: javascript node.js express middleware

我在express.js / node.js中编写了一个中间件来检查会话,如果找到了用户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,则显示用户的菜单。

我正在加载一个测试页面,我没有使用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);

2 个答案:

答案 0 :(得分:2)

你的中间件运行两次的原因是它为初始请求运行了一次,而对于404(不存在的静态脚本)运行一次。

如果WriteConcern.WMajority 可以找到一个文件,它会发送带有相应文件的响应,如果它找不到正确的文件(就像您的情况那样),它会调用express.static尝试将请求与其他路由匹配,运行在next()下面定义的任何其他中间件。

换句话说,如果express.static确实找到了要提供的文件,那么它下面的中间件将无法运行。在您的情况下,中间件针对实际请求运行一次,并且一旦尝试查找文件或正确的路由作为响应。

通过记录普通静态文件的express.static和不存在的文件可以观察到这一点:

app.js -

req.path

layout.hbs(渲染&#39; /&#39;) -

app.use(express.static(path.join(__dirname, 'public')));

app.use(function(req, res, next){
  console.log('Requested path: %s', req.path);
  next();
})

我们将看到中间件只会记录初始请求和404的请求路径,而不是静态文件。 e.g:

<!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>

希望这有帮助。

答案 1 :(得分:-1)

你在哪里应用这个中间件?

例如,如果你有

app.use(handler)

其中handler的格式为function (req, res, next),它将应用于每个请求(使用任何HTTP谓词)。或者,

app.get('/some/route', handler)

其中handler适用于/some/route以下的任何地方(例如/some/route/any/deepness)。

所以我的猜测是你过度应用中间件功能(我正在交换处理程序中间件,他们有相同的函数签名 - 也许 handler 更适合向调用next()的人发送响应和中间件的函数。但是如果没有应用这个中间件的背景,很难说。

请参阅Writing Middleware以及Express提供的其他指南。

PS。您不需要在中间件中return next()。只需next()