AngularJS remove # and have error when refresh page - angularjs

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>

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.

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.

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.

1) AngularJS
$routeProvider
.when('/path', {
templateUrl: 'path.html',
});
$locationProvider
.html5Mode(true);
2) server side, just put .htaccess inside your root folder and paste this
ewriteEngine On
Options FollowSymLinks
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /#/$1 [L]
Cheers....

Erik Honn gives a good explanation of the logic. Here's how I solved it using Jersey and Tomcat 7 with Tucky's urlrewritefilter https://github.com/paultuckey/urlrewritefilter
Add dependency using Maven or download jar.
<dependency>
<groupId>org.tuckey</groupId>
<artifactId>urlrewritefilter</artifactId>
<version>4.0.3</version>
</dependency>
Add filter mappings to the web.xml file located in WEB-INF directory. This should be within the web-app tag.
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Create a file in WEB-INF called urlrewrite.xml and add rerouting to index.html
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
"http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">
<!--
Configuration file for UrlRewriteFilter
http://www.tuckey.org/urlrewrite/
-->
<urlrewrite>
<rule>
<from>^/titles$</from>
<to>index.html</to>
</rule>
<rule>
<from>^/authors$</from>
<to>index.html</to>
</rule>
<rule>
<from>^/courses$</from>
<to>index.html</to>
</rule>
<rule>
<from>^/account$</from>
<to>index.html</to>
</rule>
</urlrewrite>
Don't forget to relaunch so that the xml is configured. It would be great if someone knew a way to bundle the routes to all go to index.html rather than having to set individual rules.

Just write this in htaccess
RewriteEngine on
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.php [L]
I dont have an index.html i have index.php so i wrote index.php instead of index.html
Cheers!

I recently found a solution to this issue that doesn't involve switching to Apache2 with a .htaccess file.
In web.xml:
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/rewrite-404.jsp</location>
</error-page>
Then create a new file in WebContent called rewrite-404.jsp:
<% response.setStatus(HttpServletResponse.SC_OK); %>
<%# include file="index.html" %>
This will cause existing files in WebContent to be served as usual, and all requests that would normally return a 404 error to return index.html instead with a 200 (OK) response code.

Related

Elastic Beanstalk: remove hashbang urls from SPA

I have an AngularJS app hosted using Elastic Beanstalk and I'd like to remove the hashbangs (#!) from urls, but am having trouble using config files to make the necessary modifications to the Apache server.
I have enabled html5mode in my angular app and I currently have the following config file in my .ebextensions directory
files:
"/etc/httpd/conf.d/wsgirewrite.conf":
mode: "000644"
owner: root
group: root
content: |
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteRule ^ /index.html
Everything works fine without the hashbangs until I reload the page and I get a 404 indicating that the rewrite rules aren't working.
If possible, I'd like to avoid any solutions that involve ssh, copying, and modifying one of the default configs as this will likely make maintenance a nightmare if AWS changes any defaults down the road
Hashbang is a fallback mechanism for older browsers, where HTML5 is not supported. Check illustration:
What you may be looking for is how to configure "pretty URLs" in AngularJS. Besides enabling HTML5 mode (which it seems you already did: $locationProvider.html5Mode(true)), you need to configure the <base href="/"> tag inside your <head>, specifying the base URL/target for all relative URLs in a document.
Note: the $location service will automatically fallback to the hashbang method for browsers that do not support the HTML5 History API.
By Angular's documentation, without #, the url looks much nicer, but it also requires server side rewrites. This is the httpd.conf example they have for Apache server:
<VirtualHost *:80>
ServerName my-app
DocumentRoot /path/to/app
<Directory /path/to/app>
RewriteEngine on
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.html [L]
</Directory>
</VirtualHost>
Since you are working with Beanstalk, you need to config httpd.conf via ebextensions. Two options available for Apache:
To override the Elastic Beanstalk default Apache configuration completely, include a configuration in your source bundle at .ebextensions/httpd/conf/httpd.conf.
To extend the Elastic Beanstalk default Apache configuration, add .conf configuration files to a folder named .ebextensions/httpd/conf.d in your application source bundle (e.g. .ebextensions/httpd/conf.d/port5000.conf).
I would recommend the extension option.
References:
https://scotch.io/tutorials/pretty-urls-in-angularjs-removing-the-hashtag
https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/java-tomcat-proxy.html
https://docs.aws.amazon.com/pt_br/elasticbeanstalk/latest/dg/ebextensions.html

AngularJS HTML5 mode with UI Router on apache

I had turned on the html 5 mode on my angular(1.5.8) app a few days back with this code:
$locationProvider.html5Mode({enabled:true,requireBase:true}).hashPrefix('!');
Later I read configuring apache server for html5 mode with ui-router.
After doing these settings, I am facing 2 problems:
Browser reload, redirects to home page for every deep nested app link.
Any link coming from outside(via email) always redirects to the homepage.
I have played with
mod_rewrite as-in using <Directory>, FallbackResource on apache.
changing paths to assets in the index.html (using relative URI and full qualified URI)
adding/removing the base HTML tag. (trying options like '/', '<sitename>')
But I am yet to overcome these problems.
Here is the detailed setup on my localhost:
I am deploying to apache via Virtual Host(and not .htaccess).
My deployment directory is /Users/<name>/Sites/<sitename> (I am on mac OS)
My index.html in-parts is as follows:
<head>
<base href="/">
<!-- SPELLS 1-->
<script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/angular.min.js"></script>
<!-- more scripts / css et al -->
</head>
My Apache(2.4.28) config is as follows:
<VirtualHost *:80>
ServerName <servername>
DocumentRoot "/Users/<name>/Sites/<sitename>"
#LogLevel debug
LogLevel debug rewrite:trace6
RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteRule ^ index.html [L]
Options Indexes FollowSymLinks
Require all granted
</VirtualHost>
Can anyone help me with the exact setup?
I'm not a fan of theL flag unless you plan on rewriting the URL more than once (it only ends the current iteration, and the rewritten URL goes through the rules again). You don't need the Indexes option and the directory test unless you want Apache to do automatic listing of directory contents. Try this:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule ^ index.html [END]

Configure Web.Config (ASP.NET) to redirect web crawlers to another page

I have a website using AngularJS running in an IIS web server. Since all the site's information is being requested via AJAX, social media crawlers are unable to parse that data. So, to prevent social media from showing empty expressions, for example: {{helloWorld}}, I'm trying to redirect some social media crawlers to a specific section in my web application that can prerender the page for the social media crawlers.
I've done this with success using an Apache .htaccess file:
RewriteCond %{HTTP_USER_AGENT} (facebookexternalhit|Facebot|Twitterbot)
RewriteRule ^(.*)$ http://myapp.com/prerender?url=%{REQUEST_URI} [P]
What i would like to know is how can i accomplish the same thing using IIS. Basically i would like configure a Web.Config file with the equivalent rewrite rule as above.
Importante, in the script above i'm using the [P] flag to informe Apache to access the prerender page without the crawler knowing that a redirection has occured.
Any ideas on how i can do this?
I was able to solve my issue.
To simply rewrite the URL to another page in the same domain, URL Rewrite must be enabled in IIS. In order to rewrite to another domain you not only need URL Rewrite, but Application Request Routing enabled in the server as well (reverse proxy).
Then just use the following example rule in web.config:
<rewrite>
<rules>
<rule name="RewriteTest" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="%{HTTP_USER_AGENT" pattern="(facebookexternalhit/[0-9]|Facebot|Twitterbot/[0-9])" />
</conditions>
<action type="Rewrite" url="http://example.com/{R:1}" />
</rule>
</rules>
</rewrite>
Hope this helps.

After ng build in Angular 2 Cli application build the refresh shows 404 Error

I have successfully create and run an angualr2-cli application. I also deploy the application on the apache server, For this I am using the help of angular2-cli command ng build
But My application goes down ( 404 Page Not Found Error) while refreshing the child pages.
Please do the following steps you will realize the problem I have mentioned.
Click this link to load the web page
Now Click the Job Side bar menu or any or the side bar element
Then refresh the page
You would able to see my problem. The page gone and show 404 Error. Why it is happen on after deploy into apache server. The refresh is perfectly work on development environment (http://localhost:4200 ) while I'm running the server using ng serve command
I have fixed this issue following this guide. That is nothing wrong in my configuration. The problem is to adding the .httaccess and allow rewrite rule on the server settings.
I summarized the steps what I have done to fix this issue.
I have added .httaccess file on the location where the index.html resides.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
2.Then allow the rewite mod on apache server using sudo a2enmod rewrite
3.The restart the apache server service apache2 restart
4.After that open the /etc/apache2/sites-enabled/000-default.conf file and add the following rule on <VirtualHost> tag
<Directory "/var/www/html">
AllowOverride All
</Directory>
That's it!! Any of the links redirect to my index.html and works. Because All of the routes are route from index.html in angular2 routing
Here is a solution for IIS server
Create web.config file that includes the following:
<!-- configure the site to work with HTML5 push state -->
<rewrite>
<rules>
<rule name="AngularJS 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 input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
Put this file in yor root deployed folder.

angular html5mode in tomcat apache 8.5.4 gives 404 on page refresh

I m creating war file using gulp-war and deploy it into tomcat apache server 8.5.4 on my system
it first runs on localhost:8080/projectName/
but whenever I refresh the page it gives 404 error . How to fix this issue?
if I remove $locationProvider.html5Mode(true); from config file and than creat war file than it working fine
than everything works fine but URl comes with /#/
I tried with adding .htaccess file but no difference
anyone has the solution ?
I found the solution with help of this article
add in /opt/tomcat/conf/context.xml
<!-- REWRITE VALVE -->
<Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />
<!-- // -->
add rewite.config file in specific project WEB-INF folder with below content such as on /opt/tomcat/webapps/projectName/WEB-INF/rewrite.config
RewriteCond %{REQUEST_URI} !^.*\.(bmp|css|gif|htc|html?|ico|jpe?g|js|pdf|png|swf|txt|xml|svg|eot|woff|woff2|ttf|map)$
RewriteRule ^(.*)$ /index.html [L]
hope it helps someone
This is example for The global approach :
<?xml version='1.0' encoding='utf-8'?>
<!-- The contents of this file will be loaded for each web application -->
<Context>
<!-- REWRITE VALVE -->
<Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />
<!-- // -->
<!-- Speed up context loading -->
<JarScanner scanClassPath="false" />
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
</Context>
And Just jave added two most popular extensions to your list:
RewriteCond %{REQUEST_URI} !^.*\.(bmp|css|gif|htc|html?|ico|jpe?g|js|pdf|png|swf|txt|xml|svg|eot|woff|woff2|ttf|map|json)$
RewriteRule ^(.*)$ /index.html [L]
I like reverse approach (comment by ) but prefer to keep it clean and readable.

Resources