Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js catch-all route with redirect always renders index page with Angular regardless of url

Essentially when I use a catch-all route and use res.redirect('/') regardless of the url I enter it will always render the index/home page (ie Angular does not seem to 'see' the full url) however if I place res.render('index') in the catch-all route everything works fine. I don't want repeat code and redirecting to '/' should work, I have probably made a stupid mistake somewhere here and any help would be much appreciated!

Angular routing:

app.config(function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);

$routeProvider
    .when('/', 
        {   
            templateUrl: 'partials/home.jade'
        })
    .when('/about', 
        {
            templateUrl: 'partials/about.jade'
        })
    .otherwise( {redirectTo: '/'});
});

This will correctly render the about page when entering site-address/about:

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

app.get('/partials/:name', function (req, res) {
    res.render('partials/' + req.params.name);
});

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

This will always just show the index page:

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

app.get('/partials/:name', function (req, res) {
    res.render('partials/' + req.params.name);
});

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

Configuration if it helps:

// Configuration
app.configure(function () {
    app.set('port', process.env.PORT || 1337);
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.use(express.favicon());
    app.use(express.logger('dev'));
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.static(path.join(__dirname, 'public')));
    app.use(app.router);
});
like image 257
adamK Avatar asked Mar 23 '23 01:03

adamK


2 Answers

This is by design.

When you use res.redirect('/'), Node/Express is sending an HTTP redirect, which will change the URL in the browser, thus when your index template is rendered, and when the angular code is run, the URL is /, regardless of what the user entered (the whole point of the redirect).

When you omit the redirect and just send the template as a response, NodeJs responds with an HTTP 200 (success) along with HTML content. Since the URL didn't change, when your application runs, the angular routing properly routes.

EDIT TO ADD: Address Comment

Rather than have two routes render the same template, I would get rid of the / route all together, and just have the catch-all render the index template, which will then turn control over to the Angular router.

Otherwise, I would consider splitting your routes conceptually: All your application routes are specifically sent to angular router, and you render static routes via nodejs, and use your catch all to render a more appropriate page for a missing or unknown resource (more helpful for your users).

You can use regex-like languages to specify a single handler:

app.get('/()|(about)|(contact)/',function(req,res) {/* handle */});
like image 55
Alan Avatar answered Apr 24 '23 18:04

Alan


For folder structure:

root
-web.js
-dist/index.html
-dist/rest of the page

Just paste the following snippet to your web.js

nodeApp.use('/', express.static(__dirname + '/dist'));
nodeApp.get('/[^\.]+$', function(req, res){
    res.set('Content-Type', 'text/html')
        .sendfile(__dirname + '/dist/index.html');
});
like image 45
Andrzej Gis Avatar answered Apr 24 '23 18:04

Andrzej Gis