捕获除/登录之外的所有路由

我目前正在编写一个 API,它将要求用户在每个请求的头部传递一个身份验证令牌。现在我知道我可以创建一个包罗万象的路线说

app.get('/*', function(req,res){


});

但是我想知道我如何使它排除某些路线,如 /login/

114642 次浏览

I'm not sure what you want to happen when a user accesses /login or /, but you can create separate routes for those; if you declare them before the catch-all, they get first dibs at handling the incoming requests:

app.get('/login', function(req, res) {
...
});


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


app.get('*', function(req, res) {
...
});

You can always place catch-all route after the ones you want to exclude (see robertklep answer).

But sometimes you simply don't want to care about the order of your routes. In this case you still can do what you want:

app.get('*', function(req, res, next) {
if (req.url === '/' || req.url === '/login') return next();
...
});

Another way to make a catch-all route handler is this:

app.get('/login', function(req, res) {
//... login page
});
app.get('/', function(req, res) {
//...index page
});
app.get('/:pageCalled', function(req, res) {
console.log('retrieving page: ' + req.params.pageCalled);
//... mypage.html
});

This works exactly like robertklep's (accepted) answer, but it gives you more information about what the user actually requested. You now have a slug req.params.pageCalled to represent whatever page is being requested and can direct the user to the appropriate page if you have several different ones.

One gotchya to watch out for (thx @agmin) with this approach, /:pageCalled will only catch routes with a single /, so you will not get /route/1, etc. Use additional slugs like /:pageCalled/:subPageCalled for more pages (thx @softcode)

If you want to validate credentials or authenticity in every request you should use Express Routing feature "all", you can use it like this:

app.all('/api/*', function(req, res, next){
console.log('General Validations');
next();
});

You could place it before any Routing stuff.

Note that in this case I used "/api/" as path, you can use "/" you it fits your needs.

Hope it is not too late to help somebody here.

Negative lookahead regex

Maybe this will come handy at times:

const app = require('express')()
app.get(/^\/(?!login\/?$)/, (req, res) => { res.send('general') })
app.get('*',                (req, res) => { res.send('special') })
app.listen(3000)

With this, you would get:

/           general
/asdf       general
/login      special
/login/     special
/login/asdf general
/loginasdf  general

Or if you also want /login/asdf to be special:

app.get(/^\/(?!login($|\/.*))/, (req, res) => { res.send('general') })

In particular, when I Googled here I was thinking about the case of serving static frontend files on the same server that does the API for a SPA:

const apiPath = '/api';
const buildDir = path.join(__dirname, 'frontend', 'build');


// Serve static files like /index.html, /main.css and /main.js
app.use(express.static(buildDir));
// For every other path not under /api/*, serve /index.html
app.get(new RegExp('^(?!' + config.apiPath + '(/|$))'), function (req, res) {
res.sendFile(path.join(buildDir, 'index.html'));
});


// Setup some actions that don't need to be done for the static files like auth.
// The negative lookahead above allows those to be skipped.
// ...


// And now attach all the /api/* paths which were skipped above.
app.get(apiPath, function (req, res) { res.send('base'); });
app.get(apiPath, function (req, res) { res.send('users'); });


// And now a 404 catch all.
app.use(function (req, res, next) {
res.status(404).send('error: 404 Not Found ' + req.path)
})


// And now for any exception.
app.use(function(err, req, res, next) {
console.error(err.stack)
res.status(500).send('error: 500 Internal Server Error')
});


app.listen(3000)

Tested on express@4.17.1, Node.js v14.17.0.