February 7, 2018

Angular Universal Handle 404 and Set Status Codes

When working with Angular Universal we can implement a full-fledged server. Of course, this does not only include for example to display a 404 page for incorrect urls but also setting the correct status code. So that for example search engines and crawlers in general can process the result correctly.

Angular itself allows us to easily create a 404 page via the router package. However, this is to be regarded as a soft 404. Because although a page is output, the HTTP status code is still 200.

In the first step we start with the trivial issue of displaying the Not-Found-Component. Afterwards we dedicate ourselves to setting the correct status code on the response object that we consume via Express. The example code assumes that you are using lazy load but you can change that.

 

Create a new module for our Not-Found-Component.

 

Add the component to the not-found-routing.module.ts file

 

Add some content to the not-found.component.html file

 

Now only the module remains to be integrated into the routing by editing our app.routes.ts file. Add the following two entries to the end of your routes array. Watch out: redirectTo has to be last!

 

So far so good. We now have a working 404 component that will be displayed when an invalid URL is accessed.

 

 

Setting the Status Code

The end users experience is covered. So lets set the correct status code. This tutorial assumes that you have followed the official Angular Universal Guide but should work for all setups using express. In our express server we have access to the request and response objects. Those are needed in the 404 component in order to set the status code each time the component is loaded. In order to do so we use the dependency injection provided by Angular.

Find the place where renderModuleFactory is used. Usually this is in the server.ts file in your projects root. It might look like this:

We are going to add some extraProviders in order to inject response and request into our Angular application. Modify your code like this:

If you are not using @nguniversal/express-engine then simply use strings as injection tokens. When your application is now running on the server you have access to the request and response obejcts. If the application is running in the browser they are empty.

Now we can extend our Not-Found-Component in order to set the correct status code.

Thats it. A hard page reload that leads to your Not-Found-Component will now result in the correct 404 error code. Feel free to leave a comment on how you liked the approach and if it worked for you!

 

 

 


Can Kattwinkel

Entwickler bei thecodecampus

Comments (11)

  1. Manjesh says:

    Works like a charm..awesome ! Thanks a ton. I have been trying to solve this for a while now. Finally found this.

  2. Manjesh says:

    BTW…Though it worked perfectly during a server side build, I got the following error with the webpack compilation:
    Critical dependency: the request of a dependency is an expression
    Had to change some bit of the code in the not-found component. For some reason, webpack does not like injecting using RESPONSE token. Injected “Injector” instead and obtained the response using the following line:
    this.injector.get(RESPONSE) as Response;

    1. Can Kattwinkel says:

      Thanks for your feedback! With the most recent version of Angular & CLI it is working for me. Instead of using the response as inejction token you can always create a string, then don’t forget to export it.

      1. Johan says:

        Same here, injector resolved the issue. Thanks 🙂

        1. Karol says:

          constructor(
          @Inject(PLATFORM_ID) private platformId: Object,
          @Inject(Injector) private injector: Injector
          ) {}

          ngOnInit() {
          if (!isPlatformBrowser(this.platformId)) {
          let response = this.injector.get(RESPONSE) as Response;
          response.status(404);
          }
          }

      2. Matt C says:

        I’m also receiving “Critical dependency: the request of a dependency is an expression”. Can you please provide an example of creating a string and exporting this?
        Also tried updating my CLI and Angular and still got the error.

    2. sumit patil says:

      can you please tell us what changes you made

  3. Valentin says:

    After adding the value provider into the app engine, I’ve got an error: Error: StaticInjectorError[NgModuleFactoryLoader -> InjectionToken MODULE_MAP]:
    StaticInjectorError(Platform: core)[NgModuleFactoryLoader -> InjectionToken MODULE_MAP]:
    NullInjectorError: No provider for InjectionToken MODULE_MAP!

    1. Can Kattwinkel says:

      Hello Valentin,

      your error isn’t really connected to the code from this blog post. Did you maybe replace the provider recipe for MODULE_MAP?

      You can find an example usage here:
      https://github.com/angular/angular-cli/wiki/stories-universal-rendering

      Good Luck!

  4. Johannes says:

    Thanks a lot! Excellent explanation!

Leave a Reply

Your email address will not be published. Required fields are marked *