10

I have a javascript that does different things depending on the URL. for that to work, i need to have consistent URIs.

for example, i need users to always be on www.site.com/users/bob/ instead of www.site.com/users/bob

node unfortunately doesn't support that, as it seems.

i tried redirecting with

router.get('/:user', function(req, res) {
    res.redirect('/users/' + req.params.user' + '/');
});

but it just results in a redirect loop, as the URL with and without slash seem to be treated as the same.

how can i do this? thanks!

edit:

i want to route from WITHOUT slash to WITH slash. the answers in the other question address the other way around. i can't .substr(-1) my URLs

Community
  • 1
  • 1
user3787706
  • 659
  • 1
  • 6
  • 18

5 Answers5

31

In case someone else is looking for a quick zero dependency solution, this worked fine for me:

app.get('/:page', function(req, res){
  // Redirect if no slash at the end
  if (!req.url.endsWith('/')) {
    res.redirect(301, req.url + '/')
  }

  // Normal response goes here
});
jncraton
  • 9,022
  • 3
  • 34
  • 49
  • 10
    This is obviously the better answer and should be marked correct instead. People shouldn't always rely on dependencies for the smallest things. – Alexander Fuchs Jun 03 '17 at 04:03
  • 3
    Are you considering queries after path? – JulianSoto Dec 02 '17 at 04:21
  • 5
    @AlexanderFuchs In my opinion the accepted answer solves the problem more completely as it considers redirect loops and query strings. I hate 2 line snippet libraries too, but there are no sub-dependencies and there's more going on here if you check out the [github source](https://github.com/ericf/express-slash/blob/master/index.js) Both methods (snippets and libraries) have their pros and cons and I guess it all depends on what the programmer requires. – Phil Dec 04 '17 at 11:37
  • This is a good solution for pages that do not accept URL params, at least. ETA: or it would be, except in a subapplication you can register as `app.use("/path/to/sub/", sub)` then when the user visits `/path/to/sub` your handler is called with `req.url == "/"`. I had to check `req.originalUrl` and it might have been easier to just register middleware at a higher level. – Coderer Aug 23 '19 at 08:37
  • Actually redirecting to `req.url` won't work for subapplications anyway, since the redirect is relative to domain root, not subapplication root. You need `originalUrl` (or something computed from `baseUrl`) for that as well. – Coderer Aug 23 '19 at 08:43
  • this will fail when user url has extension in it. ex '/static/js/main.js' => '/static/js/main.js/' . giving 404 – hannad rehman Oct 29 '19 at 13:24
  • I agree this should be top answer, but should use originalUrl like @Coderer said as just url will fail in some cases. – stackers Nov 24 '20 at 00:27
  • also doesn't support query string parameters... very limited solution – gilad905 Mar 22 '21 at 16:19
3

You can get this by using third-party library which is called express-slash . All you need to do is,

First, install the library

$ npm install express-slash

And, add these to your app.js.

var slash   = require('express-slash');

app.use(slash()); // set slash middleware

Then, this is your router.

router.get('/:user/', function(req, res) {
    // do your stuff
});

Hope it will be useful for you.

Arkar Aung
  • 3,554
  • 1
  • 16
  • 25
  • i thought more of a short snippet without the need for an external middleware, but this will have to do. thanks! – user3787706 Jan 01 '16 at 13:51
1

I'm adding this answer as a full solution that redirects non-slash routes to end with a slash.

Firstly, enable a strict router (v4+) to disable the auto normalisation.

express.Router({strict: true});

Then start your router with a catch-all route which detects if it doesn't end with a slash - and in this case also omits anything with a (.) - so images etc aren't caught.

var url = require('url');
router.all(/^[^.]*[^\/]$/, function(req, res) {
    let u = url.parse(req.originalUrl);
    return res.redirect(301, u.pathname + '/' + (u.search || ''));
});

This works with query string parameters etc.

sidonaldson
  • 24,431
  • 10
  • 56
  • 61
0

You could try jncraton's answer, but only append slashes to directories..

const path = require('path')

app.get('/*', function(req, res) {
    if (!req.url.endsWith('/') && !path.extname(req.url)) {
        res.redirect(301, req.url + '/')
    }
}
Mulhoon
  • 1,852
  • 21
  • 26
0

Set this use after the 'express.static' use and before other use methods.

This code removes the slash from the end of path if it exists, and redirects to the new URL.

If you what to add a slash you can change it so that it adds a slash if the original path doesn't have one.

app.use((req, res, next) => {
    let url = parseURL(req.url),
        pathname = url.pathname,
        search = url.search || '',
        hasSlash = pathname.charAt(pathname.length - 1) === '/';

    if (hasSlash && pathname !== '/') {
        // remove slash
        pathname = pathname.slice(0, -1);
        // redirect to truest url
        res.redirect(301, pathname + search);
    } else {
        return next();
    }
});