expressjs / express

Fast, unopinionated, minimalist web framework for node.
https://expressjs.com
MIT License
65.71k stars 16.3k forks source link

Strict Routing #3798

Open sabrehagen opened 6 years ago

sabrehagen commented 6 years ago

I've been experimenting with strict routing using express@latest and have found that the following the requests all route to the same path when supplying strict: true to express. This doesn't seem to uphold the docs explanation of Disabled by default, “/foo” and “/foo/” are treated the same by the router..

const express = require('express')
const app = express({ strict: true })
const port = 3022

app.get('/:param?/', (req, res) => res.json(req.params.param));

app.listen(port);
> curl -I http://localhost:3022/
HTTP/1.1 200 OK

> curl -I http://localhost:3022/abc
HTTP/1.1 200 OK

> curl -I http://localhost:3022/abc/
HTTP/1.1 200 OK
dougwilson commented 6 years ago

Looking at the docs on expressjs.com about it, it doesn't really say what to expect for strict routing besides "it treats /foo and /foo/ as different". There is no description for what to even expect when you have an optional parameter.

That said, the express() function does not take any argument, so the extra { strict: true } your example passes in will do as much as passing in { foo: 42 }.

We may have made a mistake in the docs. Can you point to where in the docs it says express({ strict: true }) is a thing that would do something?

ianmetcalf commented 6 years ago

@sabrehagen for the built in router you need to use app.enable('strict routing') which is documented here https://expressjs.com/en/4x/api.html#app.set

you can override this when creating a new router as documented here https://expressjs.com/en/4x/api.html#express.router

TravColbert commented 5 years ago

I have noticed that strict routing works as documented when following a route defined within a route module like this:

myroute.js

const express = require('express')
var router = express.Router({ strict: true })

module.exports = function (app) {
  router.get('/', a_middleware)
  router.get('/:id/', other_middleware)
  return router
}

When the above is attached to my main app as follows:

app.js

app.set('strict routing', true)
.
.
.
let myroute = require('path/to/myroute')
app.use(`/myroute/`, myroute)

In the above scenario https://server/myroute/8/ routes to "other_middleware" properly while https://server/myroute/8 fails. This is the desired and expected result.

However, if I pull back one level it seems that the trailing slash does not change how I'm routed: https://server/myroute/ and https://server/myroute appear to work the same and routes me to "a_middleware" in both cases.

So, where the mini-app is attached to the main app the trailing slash makes no difference in the routing.

mattdeluco commented 4 years ago

I'm encountering a similar problem. In my app, starting at a route defined at /api, each subsequent level is a new router object, all created with {strict: true}, yet when I make a request to /api/myroute, it takes the codepath defined at /api/myroute/.

The routes are defined as follows:

router.route('/').get(...).post(...);
router.route('').get(...).post(...);

Where router is mounted to the parent router with parent_router.use('/myroute', router).

A GET request to /api/myroute will take the first defined above, when I would expect it to take the second.

On my main application app.set('strict routing', true); has no apparent effect.

dbauszus-glx commented 4 years ago

The strict routing seems to work, but not as intended. There is a problem with trailing slashes being added to root paths which then become unavailable with strict routing.

const express = require('express')

const app = express()

//app.enable('strict routing')
//app.set('strict routing', true)

// Returns static files from the public subfolder.
// e.g. localhost:3000/dir/public/views/desktop.html
app.use('/dir', express.static('public'))

// This adds a trailing slash to localhost:3000/dir
app.get('/dir', (req, res) => require('./api/root')(req, res))

// This doesn't change and returns view on localhost:3000/dir/view
app.get('/dir/view', (req, res) => require('./api/root')(req, res))

// This returns JSON.
app.get('/dir/api/get', (req, res) => require('./api/get')(req, res))

app.listen(3000)

This adds a trailing slash to localhost:3000/dir and returns the view or breaks with strict routing enabled. The behavior is the same whether enabled via .set() or .enable().

const router = express.Router({ strict: true })

router.get('', (req, res) => require('./api/root')(req, res))

app.use('/dir', router)

Same behaviour here... Adds trailing slash and breaks with strict option set in the router.

jonchurch commented 4 years ago

Related https://github.com/expressjs/express/issues/2281

uzair004 commented 3 years ago

same problem, providing caseSensitive: true as option to express.Router has no effect.

egorFiNE commented 3 years ago

express.Router instantiates Layer with strict: true. However, there is no strict in layer.js. In other words, this feature is not implemented and perhaps never was.