000000000000000000000
000000000000000000000

Reputation: 880

HTML5 History API auto routing refresh error

I am currently working with a project using SpringBoot at the backend and HTML5 and Angular 2 at the frontend.

After I deploy the project, everything works fine when I navigate in the browser, until I press reload button. Browser will show error page.

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Mon May 08 10:16:14 CDT 2017

There was an unexpected error (type=Not Found, status=404).

No message available

This is apparently being caused by the use of the HTML 5 history API to store client-side navigation in the browser URL.

So when I start to click on items on the page, I see the URL automatically appends itself.

However, this becomes a problem when refresh is hit, the full appended URL is sent to server which can't understand it because a specific mapping of that appended URL doesn't exist.

Is there a fix to this that updates the server-side configuration so that any unknown URL returns a view of the root index.html view?

For example, when I hit refresh, the URL being queried is simply the root url http://localhost:8080/root, rather than the appended URL.

This will let the browser properly navigate rather than trying to do it on the server side.

Upvotes: 12

Views: 1840

Answers (5)

Arsalan Siddiqui
Arsalan Siddiqui

Reputation: 228

This happens as by default Angular is using HTML5 routing strategy. If you change the routing strategy to hash routing strategy then this will not happen. Just add "useHash: true" where you imported the RouterModule and you are all set.

RouterModule.forRoot(routes, {useHash: true})

Upvotes: 0

Preview
Preview

Reputation: 35796

Since it seems you are only using SpringBoot as a backend, you could either redirect all your requests to the index.html

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

  @Controller
  static class Routes {

    @RequestMapping(value = "/**", method = RequestMethod.GET)
    public String index() {
      return "index.html";
    }

  }

}

Or override the ErrorController to catch the /error you are seeing and redirect to your index instead

import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class OverrideController implements ErrorController {

  @RequestMapping("/error")
  public String index() {
    return "index.html";
  }

  @Override
  public String getErrorPath() {
    return "index.html";
  }

}

But I would recommend to separate entirely the frontend from the backend, by serving your angular app with something that could be as basic as Nginx, since you just need to serve static files. SpringBoot seems a bit overkill or not really fit for this purpose.

Here is a good configuration example you could look into for this purpose, which is basically a catch all to an index.html

server {
  server_name yoursite.com;
  root /usr/share/html;
  index index.html;

  location / {
    try_files $uri $uri/ /index.html;
  }
}

Upvotes: 3

user7834658
user7834658

Reputation:

I think the others are pretty good in their answers that uses natural routes, so I won't go into too much detail here.

But to answer the question of why your index.html doesn't show up, I think I have found the answer here

So basically the answer explained it this way concerning Spring Boot: "Spring Boot docs also says:

Do not use the src/main/webapp directory if your application will be packaged as a jar. Although this directory is a common standard, it will only work with war packaging and it will be silently ignored by most build tools if you generate a jar.

Spring Boot is very opinionated and works best when you do not try to resist defaults. I don't see any reason having your files placed in /src/main/webapp. Just use /src/main/resources/static for your front-end assets. That is most common place.

It will serve these static files from root URI automatically, without need to create any root level Controller. In fact your IndexController would prevent static front-end files to be served from root URI. There is no need to create Controller for static files at all.

Also view resolver is not needed for your app. Your app is just REST API consumed by single page angular application. So your HTML templating is on client. View resolvers are needed if you are doing server side HTML templating (e.g. with Thymeleaf or JSP). So remove that piece also."

I believe that you were asking about using Spring Boot, and after research on the subject for it, I believe this should be applied to you.

Upvotes: 0

Naveen Kumar
Naveen Kumar

Reputation: 50

Actually I am also getting the same problem in previously, My Project running with gulp Serve and at Localhost should be working,but at the deploy the code at server with out refershing its working once its refresh it shows the not found the path at the Time I have an idea among with the location loading at main routing giving extra '#' Like

suppose the path is 202.168.09.01/Myproject/myservice this kind of path can be change like 202.168.09.01/#/Myproject/myservice

So The # will getting actual total path of the location

I am done the issue In Angularjs, Html5.

Upvotes: 0

dave
dave

Reputation: 64657

If you look at their angular tutorial there is a relevant section "Using Natural Routes":

using a simple Spring MVC controller you can naturalize the routes in your application. All you need is a a way to enumerate the Angular routes in the server. Here we choose to do it by a naming convention: all paths that do not contain a period (and are not explicitly mapped already) are Angular routes, and should forward to the home page:

@Controller
public class SpaController {
    @RequestMapping(value = "/{[path:[^\\.]*}")
    public String redirect() {
        return "forward:/";
    }
}

Upvotes: 2

Related Questions