Reputation: 2674
I have an angular application with several routes, such as:
site.com/
site.com/page
site.com/page/4
Using angular's html5 routing mode, these resolve correctly when you click links to them from within the application, but of course are 404 errors when you do a hard refresh. To fix this, I've tried implementing a basic htaccess rewrite.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_METHOD} !OPTIONS
RewriteRule ^(.*)$ index.html [L]
This works for the angular requests, however when I try to load scripts or make ajax calls within my domain, such as:
<script src="/app/programs/script.js"></script>
This script doesn't load - it's request is redirected and it tries to load the index.html page as the .htaccess thinks it should reroute the request - not knowing that this file does exist and it should load the file instead of redirect.
Is there any way I can have the htaccess redirect the request to index.html (with the view parameters) only if there is not an actual file that it should resolve to?
Upvotes: 91
Views: 132138
Reputation: 51
I struggled to find the perfect answer for the case when you are working with a subdomain in cPanel.
Here is what worked for me.
Lets say your main domain is mysite.com
and you are using cPanel to host your site on the subdomain subdom.mysite.com
. Add a .htaccess
file in the same directory as your index.html
file, i.e., in cPanel file manager > subdom.mysite.com
directory (not in the public_html
directory).
Then write the following inside the .htaccess
file:
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
Upvotes: 1
Reputation: 2251
For Angular 2+, the following .htaccess
file works.
Here is the .htaccess
content:
<IfModule mod_rewrite.c>
RewriteEngine On
# Redirection of requests to index.html
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^.*$ - [NC,L]
# Redirect all non-file routes to index.html
RewriteRule ^(?!.*\.).*$ index.html [NC,L]
</IfModule>
If you have not created the .htacess
file yet, create it in /public_html
directory.
Upvotes: 1
Reputation: 187
The use this snippet still works. I am using cpanel for a site I created for a customer using Angular 13. I was getting the 404 error when I refreshed the page and got the same 404 error when I tried to navigate to a different page from the browser. I'm not sure when the ,htaccess code was generated on the hosting site or if it was with a tool or whether it was added when the SSL was created for this site. I added the snippet above to what was already there and it worked!
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^(www\.)?domain name\.com$ [NC]
RewriteRule ^(.*)$ https://domain name.com/$1 [L,R=301]
#Redirection of requests to index.html
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^(.*) /index.html [NC,L]
Upvotes: 0
Reputation: 1
Since angular is an AJAX application, html4 cannot implement it. All you have to do is activate the html5 mode in the .htaccess file.
angular.module('main', []).config(['$locationProvider', function($locationProvider) {
...
$locationProvider.html5Mode(true);
...
});
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
Upvotes: 0
Reputation: 8751
In my case, we needed a more feature reach .htaccess
configuration, like with:
Authorization
header to HTTP_AUTHORIZATION
environment variable.
# If mod_rewrite is not present.
<IfModule !mod_rewrite.c>
FallbackResource /index.html
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
# Prefix for all rewritten routes ("index.html" gets "/index.html").
RewriteBase /
# Redirects to HTTPS protocol (once uncommented).
#
# RewriteCond %{HTTPS} !on
# RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L]
# Make sure Authorization HTTP header is available.
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Allows access to existing files or dirs.
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
# Prevents treating the main-script as a route.
RewriteRule ^index\.html$ - [L]
# Redirect anything else to main-script
RewriteRule ^(.*) index.html [NC,L]
</IfModule>
# Enable Cross-Origin Resource Sharing (CORS)
#
<IfModule mod_headers.c>
Header merge Vary Origin
# Allows any origin (just like "*", but works in more cases)
SetEnvIf Origin "^(http(s)?://[^/:]*(?::\d{1,5})?)?" REQUEST_ORIGIN=$1
Header always append Access-Control-Allow-Origin %{REQUEST_ORIGIN}e env=REQUEST_ORIGIN
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE"
Header always set Access-Control-Allow-Headers "*"
Header always set Access-Control-Expose-Headers "*"
</IfModule>
# Disables Browser caching for production (edit pattern as you wish).
#
#<FilesMatch "\.(html|htm|js|json|css)$">
# # Ensures "Expires" header is not overridden by module.
# <IfModule mod_expires.c>
# ExpiresActive Off
# </IfModule>
# <IfModule mod_headers.c>
# FileETag None
# Header unset ETag
# Header unset Pragma
# Header unset Cache-Control
# Header unset Last-Modified
# Header set Pragma "no-cache"
# Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
# Header set Expires "Mon, 10 Apr 1972 00:00:00 GMT"
# </IfModule>
#</FilesMatch>
Note: We use [L]
instead of [L,R=301]
as the latter causes Browser to cache redirects permanently
(and even if someday that route is a file it will still get redirected).
Upvotes: 1
Reputation: 1738
There is a great "Angular .htaccess
generator" available on julianpoemp.github.io/ngx-htaccess-generator/.
The generator is open-source (the source code can be found on github.com/julianpoemp/ngx-htaccess-generator).
The generated .htaccess
looks like this by default and works fine for me:
# Generated with ngx-htaccess-generator v1.2.0
# Check for updates: https://julianpoemp.github.io/ngx-htaccess-generator/
#
# Transparency notice: Some parts were extracted from
# Apache Server Configs v5.0.0 | MIT License
# https://github.com/h5bp/server-configs-apache
# Extracted parts are wrapped by "START Extract from ASC"
<IfModule mod_rewrite.c>
RewriteEngine On
# Redirection of requests to index.html
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^.*$ - [NC,L]
# Redirect all non-file routes to index.html
RewriteRule ^(?!.*\.).*$ index.html [NC,L]
</IfModule>
Successfully tested with Angular 13.0.3
.
Upvotes: 2
Reputation: 736
In my case i create .htaccess file like below
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^(.*) ./index.html [NC,L]
just added . before /index.html and add that file in my domain like https://example.com/subfolder and it's works fine
Upvotes: 11
Reputation: 5460
Use a snippet like:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^(.*) /index.html [NC,L]
This will skip to the actual resource if there is one, and to index.html
for all AngularJS routes.
Upvotes: 182
Reputation: 857
Check out this link : https://stackoverflow.com/a/49455101/5899936
Create .htaccess
file in root folder and pase this in the .htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
Upvotes: 6
Reputation: 1299
I will provide another detailed htaccess file in case you need to :
Here is my htaccess, very close, but more specific :
DirectoryIndex index.html
RewriteEngine on
RewriteBase /subDir
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^(.*) index.html [NC,L]
Upvotes: 2
Reputation: 5613
A poor man's solution (not using mod_rewrite):
ErrorDocument 404 /index.html
Upvotes: 9
Reputation: 429
There is a problem if app requested directive
template file, but file is missing. In some case it caused app requested multiple script file in the index.html
.
we should send 404
response instead of index.html
file if file does not exist. So i add simple regex pattern to identify missing file request.
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 pattern is file and file doesn't exist, send 404
RewriteCond %{REQUEST_URI} ^(\/[a-z_\-\s0-9\.]+)+\.[a-zA-Z]{2,4}$
RewriteRule ^ - [L,R=404]
# otherwise use history router
RewriteRule ^ /index.html
Upvotes: 24