Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS remove # and have error when refresh page

I have AngularJS webapp and start it with Tomcat 7. Using $locationProvider.html5Mode(true) I remove hash '#' from url

localhost:8080/App/#/login -> localhost:8080/App/login

But now, when I refresh localhost:8080/App/login I have 404 error. How to configure Tomcat7 for localhost:8080/App/login refresh?

app.config:

$urlRouterProvider.otherwise("/login/");

$stateProvider
        .state('home', {
            abstract: true,
            templateUrl: 'dist/view/home.html',
            controller: 'HomeCtrl'
        });

$locationProvider.html5Mode(true);

index.html:

<head>
    <meta charset="utf-8">
    <script>
        document.write('<base href="' + document.location + '" />');
    </script>
</head>
like image 388
somebody Avatar asked Oct 01 '15 12:10

somebody


3 Answers

It's because when you do a full reload you always send a a request to the server with the current url. Since Angular has not loaded yet it can't handle the route, and the server doesn't know anything about what routes exist in angular and not

Without html5mode Angular uses fragmented urls of the type www.example.com/#/page. # was originally used for anchor-links so by convention the fragment part of the url is completely ignored by the server. To the server that above request would be the same as just www.example.com/, which is probably where you index.html is located. So reloading your page will in this case get your index.html, which will load Angular, which will in turn handle the fragment part of the url (#/page).

With html5mode however the fragment is hidden, and the url looks like a normal url, www.example.com/page. But when you reload the page the server doesn't get the fragment so it tries to find whatever is served under /page, which is probably nothing. Giving you a 404, Angular cannot load since index.html is not loaded, and you have a broken page.

The usual way to fix this is to have the server serve index.html under all urls that does not match a static asset (or the pattern of one). So if you request say an image it will find it and return it ok, but if you request /page (and it does not exist as a static asset) then it returns index.html. Then Angular will start, read the url and trigger the correct route.

I have only done this in nginx so I don't know how Tomcat would do it, but the principle should be the same.

like image 55
Erik Honn Avatar answered Oct 09 '22 21:10

Erik Honn


1) Download urlrewritefilter-4.0.3.jar

2) Create WEB-INF folder in root directory where index.html is present.

3) Create lib folder in WEB-INF & put downloaded jar file into it.

4) Create web.xml file in WEB-INF . Put following code into it.

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee                  http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata complete="true">
<display-name>Welcome to Tomcat</display-name><description>Welcome to Tomcat</description><welcome-file-list><welcome-file>index.html</welcome-file></welcome-file-list>
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class></filter><filter-mapping><filter-name>UrlRewriteFilter</filter-name><urlpattern>/*</url-pattern><dispatcher>REQUEST</dispatcher>   <dispatcher>FORWARD</dispatcher></filter-mapping></web-app>

5) Create urlrewrite.xml file WEB-INF

put following code into it

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE urlrewrite PUBLIC-//tuckey.org//DTD UrlRewrite 3.2//EN"
    "http://tuckey.org/res/dtds/urlrewrite3.2.dtd"><urlrewrite>

<rule enabled="true">
    <from>/[0-9_-a-zA-Z\/]+$</from>

    <to>/%{context-path}/</to>
</rule>/urlrewrite>

This is using Tomcat 7 & Tucky's urlrewritefilter https://github.com/paultuckey/urlrewritefilter

@mhatch. To budle the routes to all go to index.html, you can try this rewrite rule :

<rule enabled="true">
    <from>/[0-9_-a-zA-Z\/]+$</from>

    <to>/%{context-path}/</to>

This worked for me.

like image 1
Sneha Avatar answered Oct 09 '22 19:10

Sneha


If you want to remove the hash (#), you must use rewrite function in server to serve the index.html for all path. If not, you will always receive 404 error. It's mean you can redirect the 404 to index.html.

Apache: add a rewrite rule to the .htaccess file as show here:

RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html

NGinx: use try_files, as described in Front Controller Pattern Web Apps, modified to serve index.html:

try_files $uri $uri/ /index.html;

IIS: add a rewrite rule to web.config, similar to the one shown here:

<system .webserver="">
  <rewrite>
    <rules>
      <rule name="Angular Routes" stopprocessing="true">
        <match url=".*">
        <conditions logicalgrouping="MatchAll">
          <add input="{REQUEST_FILENAME}" matchtype="IsFile" negate="true">
          <add input="{REQUEST_FILENAME}" matchtype="IsDirectory" negate="true">
        </add></add></conditions>
        <action type="Rewrite" url="/">
      </action></match></rule>
    </rules>
  </rewrite>
</system>

In tomcat, you can add it into the web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <error-page>
        <error-code>404</error-code>
        <location>/</location>
    </error-page>
</web-app>

After redirect the web path to index.html, the HTML5 History API will be used in Angular JS to control the web route. Our main task here is just let index.html be called in server.

like image 1
Sakata Gintoki Avatar answered Oct 09 '22 20:10

Sakata Gintoki