bluray
bluray

Reputation: 1953

Angular deployment - 404 on page Refresh

i would like to deploy my app in Angular to production server but I have problems. App works corectly when I use only angular routing (change component, not redirecting) but when I refresh the page in browser, I get a 404 page returned from IIS (I use IIS as the web server)

Here is my angular routing:

const appRoutes: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full', canActivate: [AuthGuard] },
    { path: 'home', component: DashboardComponent, canActivate: [AuthGuard] },
    { path: "profile", component: UserProfileComponent, canActivate: [AuthGuard] },
    { path: '400', component: ErrorComponent },
    { path: '401', component: ErrorComponent },
    { path: '403', component: ErrorComponent },
    { path: '404', component: ErrorComponent },
    { path: '500', component: ErrorComponent },
    { path: '503', component: ErrorComponent },
    { path: '**', redirectTo: '/404' }
]

Upvotes: 14

Views: 30925

Answers (7)

Shaan Ansari
Shaan Ansari

Reputation: 550

This will work on following servers.

Apache Server

Add .htaccess on root to your project

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.html [L]
</IfModule>

IIS Server

Add web.config

<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Imported Rule 1" stopProcessing="true">
          <match url="^(.*)/$" ignoreCase="false" />
          <conditions>
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
          </conditions>
          <action type="Redirect" redirectType="Permanent" url="/{R:1}" />
        </rule>
        <rule name="Imported Rule 2" stopProcessing="true">
          <match url="^" ignoreCase="false" />
          <conditions>
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
          </conditions>
          <action type="Rewrite" url="index.html" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

Nginx Server

make changes on server file Instead of using: try_files $uri $uri/ =404;

try using: try_files $uri $uri/ /index.html;

        server {
                listen 80;
                listen [::]:80;
        
                root /var/www/example.com/html;
        
            index index.html index.htm index.nginx-debian.html;
        
                server_name example.com www.example.com;
        
                location / {
                    try_files $uri $uri/ /index.html;
                 }
        }

Upvotes: 9

Linh Dao
Linh Dao

Reputation: 1653

I fix this bug by adding { useHash: true } to RouterModule.forRoot() in the app.module.ts or app-routing.module.ts. For example:

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    RouterModule.forRoot(routes, { useHash: true })  // .../#/crisis-center/
  ],
  declarations: [
    AppComponent,
    PageNotFoundComponent
  ],
  providers: [

  ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

Upvotes: 0

mpalencia
mpalencia

Reputation: 5997

This worked for me:

  1. Add web.config to /src

     <configuration>
     <system.webServer>
         <rewrite>
             <rules>
                 <rule name="redirect all" stopProcessing="true">
                     <match url="^(.*)$" ignoreCase="false" />
                     <conditions logicalGrouping="MatchAll">
                         <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" pattern="" ignoreCase="false" />
                     </conditions>
                     <action type="Rewrite" url="./" appendQueryString="true" />
                 </rule>
             </rules>
         </rewrite>
     </system.webServer></configuration>
    
  2. On angular.json, on asset add

    "src/web.config"

Upvotes: 0

storsoc
storsoc

Reputation: 327

My initial workaround was to just redirect on 404 back to root, and so far, I don't see a down-side to this. To my surprise, both the request path and parameters persist when refreshing. This is in an IIS 10 environment with Angular 9, and a Chrome-only (internal app) so there may be other factors at play that I'm unaware of that are only making this seem sustainable. Will try to remember to come back to my answer should we discover something.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpErrors>
            <remove statusCode="404" subStatusCode="-1" />
            <error statusCode="404" prefixLanguageFilePath="" path="/" responseMode="ExecuteURL" />
        </httpErrors>
    </system.webServer>
</configuration>

Upvotes: 1

Segun Adeniji
Segun Adeniji

Reputation: 390

This work for angular 8, add .htaccess to your project file

<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
    Options -MultiViews -Indexes
</IfModule>

RewriteEngine On

# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]

# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [L]

Upvotes: 21

Nimezzz
Nimezzz

Reputation: 1864

If you are using angular 6,7 this method works (If you are okay with /#/ in your URL.

In app.module.ts

import {LocationStrategy, HashLocationStrategy} from '@angular/common';

After import add following line to providers.

{provide: LocationStrategy, useClass: HashLocationStrategy}

ex:

providers: [AuthService, 
            AuthGuard, 
            FlxUiDataTable,
            {provide: LocationStrategy, useClass: HashLocationStrategy}]

This will solve your issue. Read Documentation here.

Upvotes: 12

bluray
bluray

Reputation: 1953

I modified the web.config in my app:

<configuration>
  <system.webServer>
<rewrite>
    <rules>
        <rule name="redirect all" stopProcessing="true">
            <match url="^(.*)$" ignoreCase="false" />
            <conditions logicalGrouping="MatchAll">
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" pattern="" ignoreCase="false" />
            </conditions>
            <action type="Rewrite" url="./" appendQueryString="true" />
        </rule>
    </rules>
</rewrite>
  </system.webServer>
</configuration>

In index.html is <base href="./">. Refreshing the page is now ok.

Upvotes: 10

Related Questions