Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS and Handling 404 Errors

What is the best way to serve up proper 404's with an AngularJS app?

A little background: I'm building an Angular app and have opted to use

$locationProvider.html5Mode(true);

because I want the URLs to appear natural (and indistinguishable from a multi-page "traditional" web app).

On the server side (a simple Python Flask app), I have a catch-all handler that redirects everything to the angular app:

@app.route('/', defaults={'path': ''})
@app.route('/<path>')
def index(path):
    return make_response(open('Ang/templates/index.html').read())

Now, I'm trying to figure out what to do with 404 errors. Most of the Angular apps I've seen do the following:

.otherwise({ redirectTo: '/' })

which means that there is no way they can serve up a proper 404.

However, I would much rather return a proper 404, with a 404 status code (mainly for SEO purposes).

What is the best way to handle 404s with Angular? Should I not worry about it and stick with a catch-all? Or should I remove the catch-all and serve up proper 404's on the server side?

edited for clarity

like image 660
Ryan Shea Avatar asked Jul 08 '13 04:07

Ryan Shea


People also ask

Why 404 error in Angular?

The app throws The requested URL was not found on this server message (Status code 404 not found). It appears that angular routing not working on the production server when you refresh the page. When you type the URL directly in the address bar. The error appears on all the pages except the root page.


3 Answers

I think you are confusing Flask routes with Angular routes.

The 404 error code is part of the HTTP protocol. A web server uses it as a response to a client when the requested URL is not known by the server. Because you put a catch-all in your Flask server you will never get a 404, Flask will invoke your view function for any URLs that you type in the address bar. In my opinion you should not have a catch-all and just let Flask respond with 404 when the user types an invalid URL in the address bar, there is nothing wrong with that. Flask even allows you to send a custom page when a 404 code is returned, so you can make the error page look like the rest of your site.

On the Angular side, there is really no HTTP transaction because all the routing internal to the application happens in the client without the server even knowing. This may be part of your confusion, Angular links are handled entirely in the client without any requests made to the server even in html5mode, so there is no concept of a 404 error in this context, simply because there is no server involvement. An Angular link that sends you to an unknown route will just fall into the otherwise clause. The proper thing to do here is to either show an error message (if the user needs to know about this condition and can do something about it) or just ignore the unknown route, as the redirectTo: '/' does.

This does not seem to be your case, but if in addition to serving the Angular application your server implemented an API that Angular can use while it runs, then Angular could get a 404 from Flask if it made an asynchronous request to this API using an invalid URL. But you would not want to show a 404 error page to the user if that happened, since the request was internal to the application and not triggered by the user directly.

I hope this helps clarify the situation!

like image 76
Miguel Avatar answered Oct 19 '22 13:10

Miguel


After playing around for a bit, as well as some discussions with Miguel, I compiled a few different solutions:

  1. Just use a catch-all and don't worry about proper 404's. This can be set up with server-side code (like in my original solution), or better, with URL re-writing on your web server.
  2. Reserve a certain section of your site for your angular app (like /app). For this section, set up a catch-all and don't worry about proper 404's. Your other pages will be served up as regular pages and visiting any invalid URL that doesn't start with /app will result in a proper 404.
  3. Continuously make sure that all of your routes in app.js are mirrored in your server-side code (yes, pretty annoying), where you'll have those routes serve up your angular app. All other routes will 404.

P.S. The second option is my personal favorite. I've tried this out and it works quite well.

like image 18
Ryan Shea Avatar answered Oct 19 '22 12:10

Ryan Shea


This is an old thread, but I cam across it while searching for the answer.

Add this to the end of your appRoutes.js and make a 404.html view.

.when('/404', {
    templateUrl: 'views/404.html',
    controller: 'MainController'
})

.otherwise({ redirectTo: '/404' })
like image 2
Rusty Avatar answered Oct 19 '22 12:10

Rusty