2

Expressベースのサーバーに認証を追加しようとしています。ルーティングの奇妙な動作に気づいています。

私はこのExpressコードに問題を蒸留しました:

app.get('/', function (req, res) {
    console.log('this is reached first');
    res.send('Hello');
});

app.get('/', function (req, res) {
    console.log('this is not reached');
});

app.get('*', function (req, res) {
    console.log('this is reached');
});

'/'を要求すると、最初のハンドラーが呼び出されます。応答を提供し、next()を呼び出しません。したがって、3番目のハンドラー('*')も呼び出されているのを見て驚いています!もう1つの驚きは、3番目のハンドラーに渡される応答('res')が、最初のハンドラーに渡される応答と同じではないことです。(1番目のハンドラーからnext()を呼び出すと、同じ応答オブジェクトで2番目のハンドラーが呼び出されます。)

さて、私の実際のシナリオでは、リクエストを処理し、グローバルな方法で認証を検証したいと思います。ただし、一部のルートは、認証されていないユーザーが引き続き使用できるようにする必要があります。私は自分の解決策をZikesの答えに基づいています。最初に「フリー」パスをルーティングしました。次に、すべてのルートハンドラー('*')を含めました。ユーザーが認証されている場合はnext()を呼び出し、それ以外の場合はnext(err)を呼び出します。以下はすべての「制限された」ルートです。そして最後に、app.useを使用した私自身のエラーハンドラー。これは次のようになります。

app.use(app.router);
app.use(function(err, req, res, next) {
    console.log('An error occurred: ' + err);
    res.send(401, 'Unauthorized');
});

app.get('/', function (req, res) {
    res.send('Hello all');
});

app.all('*', function (req, res, next) {
    if (req.user) {
        next(); // authorized
    } else {
        next(new Error('401')); // unauthorized
    }
});

app.get('/members', function (req, res) {
    res.send('Hello member');
});

これはかなりうまく機能し、「/members」へのアクセスをブロックします。ただし、バグがあります。制限されていないパス('/')にアクセスしている場合でも、認証チェックとエラー処理が発生します。目的の応答が送信された後、エラーハンドラは401エラー応答を送信しようとします。後者は送信されませんが、コードは実行されません。

また、このメカニズムの副作用は、認証されていないユーザーが存在しないページに対して401エラーを受け取ることです。そのような場合には、404を返したいと思うかもしれません。しかし今、私はそれをプッシュしています...

私はちょっと2つの質問があります:

  1. この動作はバグですか?次に呼び出されることなく、ジェネラルハンドラーを呼び出す必要がありますか?
  2. 個別にマークを付けることなく、すべてではないが多くのルートをフックするための良い解決策は何でしょうか?
4

3 に答える 3

2

最初の質問については、ブラウザが複数のリクエストを送信していると思います。

たとえば、http://localhost:3000/Chromeを閲覧すると、http://localhost:3000/favicon.ico

次のようなものでキャッチされているリクエストを印刷できます。

app.get('*', function (req, res) {
    console.log('this is reached');
    console.log('url ' + req.url );
});
于 2012-10-09T13:00:30.300 に答える
1

まず、ホーム(favicon.ico)を押すときに、おそらく2つのリクエストがあります。app.use(express.logger('dev'))リクエストをログに記録するために使用します。また、そのパスをブロックしてみることができます。

app.use('/favicon.ico', function(req, res) {
  console.log('FAVICON')
  res.send(404)
}

次に、エラーを処理する必要があります。エラーを送信する良い方法:

var err = new Error('this is my error message.')
err.status = 404 // You want to send a "Not Found" page
next(err)

app.use(function(err, req, res, next) {
  var status = err.status
  if (status === 404) res.send(404, 'Page not found.');
  else res.send(500, 'Something went wrong.');
})

処理されるすべてのエラーにはステータスが必要です。

于 2012-10-10T06:09:39.010 に答える
1
app.get('/', function(req, res, next) {
    console.log('this is reached first.');
    next();
}, function (req, res) {
    console.log('this is reached last.');
    res.send('Hello all');
});

私は通常、次のように構築します。

var auth = require('../modules/authenticate');

app.get('/', auth.requireLogin, routes.index.get);
app.delete('/items/:id', auth.requireLogin, auth.permission.item.delete, routes.item.delete);
于 2012-10-09T17:44:08.463 に答える