Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

refreshing the page results in 404 error- Angular 6

Tags:

angular6

I am building an application with the help of Angular6 and facing problems in routing. All the routes are working when I click on a particular tab but whenever I refresh the current page, it is throwing 404 error. I have seen many posts regarding this issue on Stack overflow but failed to overcome from this problem.

Below is my app.module.ts

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {AppComponent} from './app.component';
import {FetchApiComponent} from './fetch-api/fetch-api.component';
import {FormsModule} from '@angular/forms';
import {HttpClientModule} from '@angular/common/http';
import {UserServiceLatest} from './fetch-latest/app.service';
import {UserServiceTop} from './fetch-top/app.service';
import {YoutubePlayerModule} from 'ngx-youtube-player';
import {SidebarComponent} from './sidebar/sidebar.component';
import {FetchLatestComponent} from './fetch-latest/fetch-latest.component';
import { FetchTopComponent } from './fetch-top/fetch-top.component'
import {UserService} from './fetch-api/app.service';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { AngularFireModule } from 'angularfire2';
import * as firebase from 'firebase';
import { firebaseConfig } from './../environments/firebase.config';
import { AngularFireDatabaseModule } from 'angularfire2/database';
import {PushService} from './push.service';

const appRoutes: Routes = [
  {
    path: '',

  component: FetchApiComponent
  }, 
{
    path: '/latest',

    component: FetchLatestComponent
  },
{
    path: '/top',

    component: FetchTopComponent
  },
{
path :'*',
component: FetchApiComponent 
}

];

firebase.initializeApp(firebaseConfig);

@NgModule({
  declarations: [
    AppComponent,
    FetchApiComponent,SidebarComponent, FetchLatestComponent, FetchTopComponent
  ],
  imports: [
    RouterModule.forRoot(appRoutes),
    BrowserModule, YoutubePlayerModule,
    FormsModule,
    AngularFireModule.initializeApp(firebaseConfig),
    AngularFireDatabaseModule,environment.production ?ServiceWorkerModule.register('firebase-messaging-sw.js'):[],ServiceWorkerModule.register('/firebase-messaging-sw.js', { enabled: environment.production }),
    HttpClientModule,environment.production ? ServiceWorkerModule.register('ngsw-worker.js') : [], ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
  ],
  providers: [UserService,UserServiceTop,UserServiceLatest,PushService],

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

Can you point me in right direction?

like image 757
N Sharma Avatar asked Jun 18 '18 10:06

N Sharma


5 Answers

You will see in your example url, that once you get the 404 error you can't make it work, but if you include a hash before the angular-specific url like /#latest it will work.

Why stops working when refreshing? your webserver is intercepting the GET request from your browser and is trying to go directly to the directory /latest, which doesn't exist. It doesn't know that it needs to go to /bosv2, find an angular app, and then add the small ending bit to your path which is a not-real directory but a routing for angular. In your local it would work as when you are doing ng serve, webpack webserver is prepared for this, but not the host where you are hosting the app.

By default, angular is using HTML5 style navigation, but with your current webserver settings you would need the old angularjs style (with hash#).

From here, you have two solutions:

  1. Change your webserver configuration
  2. Tell Angular to use HashLocationStrategy (perfectly valid solution), you can go old-school with the HashLocationStrategy by providing the useHash: true in an object as the second argument of the RouterModule.forRoot in the AppModule.

    @NgModule({ imports: [ ... RouterModule.forRoot(routes, { useHash: true }) // .../#/latest/ ], ...

I would say going the hash style has a couple of downsides, which may not be relevant in your scenario:

  1. It doesn't produce the clean and SEO Friendly URLs that are easier for users to understand and remember.
  2. You can't take advantage of the server-side rendering.

Hope you find this answer helpful :)

like image 136
Javier Aviles Avatar answered Nov 17 '22 06:11

Javier Aviles


To avoid using hashed routes, you must edit your webserver configuration properly, which is the best solution. You just have to configure it so it fallbacks to index.html, which is Angular's bootstrap. Although there is no universal configuration for this, here are some:

Apache

Add a rewrite rule to .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

Nginx

Use try_files in your location block

try_files $uri $uri/ /index.html;

IIS

Add a rewrite rule to web.config

<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" />
        </conditions>
        <action type="Rewrite" url="/index.html" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

GitHub Pages

You can't configure it directly, but you can add a 404 page. Copy index.html into 404.html in the same directory or add a symlink: ln -s index.html 404.html.

Firebase hosting

Add a rewrite rule.

"rewrites": [ {
  "source": "**",
  "destination": "/index.html"
} ]

Source: https://angular.io/guide/deployment#server-configuration

like image 36
GTX Avatar answered Nov 17 '22 08:11

GTX


With .htaccess you can try with following way also:

<IfModule mod_rewrite.c>
    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]
</IfModule>
like image 28
bharat Avatar answered Nov 17 '22 08:11

bharat


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.

like image 10
Nimezzz Avatar answered Nov 17 '22 07:11

Nimezzz


Add .htaccess file to your src folder.

.htaccess file

<IfModule mod_rewrite.c>
    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]
</IfModule>

Load .htaccess file in your build directory dist by adding it to assets in angular.json

"assets": [
     "src/favicon.ico",
     "src/assets",
     "src/.htaccess"
],
like image 9
Bhadresh Arya Avatar answered Nov 17 '22 08:11

Bhadresh Arya