refreshing the page results in 404 error- Angular 6 - 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?

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:
Change your webserver configuration
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:
It doesn't produce the clean and SEO Friendly URLs that are easier for users to understand and remember.
You can't take advantage of the server-side rendering.
Hope you find this answer helpful :)

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

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>

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.

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"
],

I think you are getting 404 because your are requesting http://localhost/route which doesn't exist on tomcat server. As Angular 2 uses html 5 routing by default rather than using hashes at the end of the URL, refreshing the page looks like a request for a different resource.
When using angular routing on tomcat you need to make sure that your server will map all routes in your app to your main index.html while refreshing the page. There are multiple way to resolve this issue. Whichever one suits you you can go for that.
1) Put below code in web.xml of your deployment folder :
<error-page>
<error-code>404</error-code>
<location>/index.html</location>
</error-page>
2) You can also try using HashLocationStrategy with # in the URL for routes :
Try using:
RouterModule.forRoot(routes, { useHash: true })
Instead of:
RouterModule.forRoot(routes)
With HashLocationStrategy your urls gonna be like:
http://localhost/#/route
3) Tomcat URL Rewrite Valve : Re-write the url's using a server level configuration to redirect to index.html if the resource is not found.
3.1) Inside META-INF folder create a file context.xml and copy the below context inside it.
<? xml version='1.0' encoding='utf-8'?>
<Context>
<Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />
</Context>
3.2) Inside WEB-INF, create file rewrite.config(this file contain the rule for URL Rewriting and used by tomcat for URL rewriting). Inside rewrite.config, copy the below content:
RewriteCond %{SERVLET_PATH} !-f
RewriteRule ^/(.*)$ /index.html [L]

Starting with Apache 2.4, you can use the FallbackResource directive instead of rewriting, so it will look like:
FallbackResource /index.html
If you have a different base href (say, /awesomeapp), change it for:
<Location /awesomeapp>
FallbackResource /awesomeapp/index.html
</Location>

If you are using cpanel then it is easy to solve this issue.
Go to Advanced Options
Step 1: Go to Error Pages.
Step 2: Copy your index.html code and paste it in 404.shtml.
That's it technically all your routes are redirected to index.html file. That's what angular wants :) and everything will work normal.
Here are some reference links
Namecheap Error Page Config
Godaddy Error Page config

In my case i did following thing
Method 1 :
in your app.module.ts import below thing
import { HashLocationStrategy, LocationStrategy } from '#angular/common';
#NgModule({
declarations: [...],
imports: [...],
providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}],
bootstrap: [AppComponent]
})
and build with
ng build --base-href /[PROJECT_NAME]/
method 2 :
for nginx,
nano /etc/nginx/sites-available/default
add follwing line in location block
location /[PROJECT_NAME] {
try_files $uri $uri/ /[PROJECT_NAME]/index.html;
}
sudo service nginx restart
and build with
ng build --base-href /[PROJECT_NAME]/

Refetch data on same URL navigation
imports: [RouterModule.forRoot(routes, {
onSameUrlNavigation: 'reload' })],

Make an .htaccess file and add this code; routes will start working:
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteRule ^ /index.html

Related

Angular app being able to access json file under assets folder in Microsoft Azure

Currently i have an angular 9 app which is able to access config.json file placed under assets folder.I have config service which is responsible for reading from this file. This works with no issues when i run locallly. The file path is /dist/assets/config.json.
However when i deploy this app on azure as Azure App Service (windows OS) strangely the app cannot find this config.json file even though i can clearly see the file is under assets folder. Below are the relevant code from each file. The code fails when the config service tries to grab the file config.json with an error message
Error occured while grabbing config files
config.service.ts:65 TypeError: You provided 'undefined' where a stream was expected. You can provide
an Observable, Promise, Array, or Iterable.
at subscribeTo (subscribeTo.js:27)
at subscribeToResult (subscribeToResult.js:11)
at MergeMapSubscriber._innerSub (mergeMap.js:59)
at MergeMapSubscriber._tryNext (mergeMap.js:53)
at MergeMapSubscriber._next (mergeMap.js:36)
at MergeMapSubscriber.next (Subscriber.js:49)
at Observable._subscribe (subscribeToArray.js:3)
at Observable._trySubscribe (Observable.js:42)
at Observable.subscribe (Observable.js:28)
at MergeMapOperator.call (mergeMap.js:21)
appmodule.ts
function configFactory(configService: ConfigService) {
return () => configService.loadConfig();
}
providers: [
{
provide: APP_INITIALIZER,
deps: [ConfigService],
multi: true,
useFactory: configFactory
},
ConfigService.ts
loadConfig() {
return this.http.get<Config>("assets/config.json").subscribe(x=>{
console.log("Successfully grabbed config files");
this.config=x;
},error=>{
console.log("Error in grabbing config files");
console.log(error);
});
}
web.config
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<system.webServer>
<staticContent>
<!-- this is so that app can find json file when deployed in azure -->
<mimeMap fileExtension=".json" mimeType="application/json" />
</staticContent>
</system.webServer>
angular.json
"assets": [
"src/favicon.ico",
"src/assets",
"src/web.config"
],
I also referred to this link Angular app unable to find asset files on Azure but the solution proposed there doesnt work in my case. I have also set "allowSyntheticDefaultImports": true in my tsconfig.app.json file.
ng build --prod --base-href /unrc-willis-web/
Or Try
ng build --prod --base-href "./"
Also interceptor had issues. interceptor was getting used for a non required call

Refreshing Angular page breaks the webpage due to bad routing [duplicate]

This question already has answers here:
Angular 2.0 router not working on reloading the browser
(32 answers)
Closed 6 years ago.
I have stored my single-page application in my server within a folder named as "myapp". I have changed the URL in the base to http://example.com/myapp/`.
My project has two pages. So I implement Angular 2 routing. I set the default page as login. When I type http://example.com/myapp/ in my browser it will redirect automatically to http://example.com/myapp/login. But if refresh that page I get a 404 error, saying that http://example.com/myapp/login is not found.
But if I run my project using the lite server everything is working. In this case the base URL in index.html will be "/". How do fix it?
Update for Angular 2 final version
In app.module.ts:
Add imports:
import { HashLocationStrategy, LocationStrategy } from '#angular/common';
And in NgModule provider, add:
{provide: LocationStrategy, useClass: HashLocationStrategy}
Example (app.module.ts):
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { HashLocationStrategy, LocationStrategy } from '#angular/common';
#NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}],
bootstrap: [AppComponent],
})
export class AppModule {}
Alternative
Use RouterModule.forRoot with the {useHash: true} argument.
Example:(from angular docs)
import { NgModule } from '#angular/core';
...
const routes: Routes = [//routes in here];
#NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(routes, { useHash: true })
],
bootstrap: [AppComponent]
})
export class AppModule { }
For people (like me) who really want PathLocationStrategy (i.e. html5Mode) instead of HashLocationStrategy, see How to: Configure your server to work with html5Mode from a third-party wiki:
When you have html5Mode enabled, the # character will no longer be used in your URLs. The # symbol is useful because it requires no server side configuration. Without #, the URL looks much nicer, but it also requires server side rewrites.
Here I only copy three examples from the wiki, in case the Wiki get lost. Other examples can be found by searching keyword "URL rewrite" (e.g. this answer for Firebase).
Apache
<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>
Documentation for rewrite module
nginx
server {
server_name my-app;
root /path/to/app;
location / {
try_files $uri $uri/ /index.html;
}
}
Documentation for try_files
IIS
<system.webServer>
<rewrite>
<rules>
<rule name="Main Rule" 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="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
In fact, it's normal that you have a 404 error when refreshing your application since the actual address within the browser is updating (and without # / hashbang approach). By default, HTML5 history is used for reusing in Angular2.
To fix the 404 error, you need to update your server to serve the index.html file for each route path you defined.
If you want to switch to the HashBang approach, you need to use this configuration:
import {bootstrap} from 'angular2/platform/browser';
import {provide} from 'angular2/core';
import {ROUTER_PROVIDERS} from 'angular2/router';
import {LocationStrategy, HashLocationStrategy} from '#angular/common';
import {MyApp} from './myapp';
bootstrap(MyApp, [
ROUTER_PROVIDERS,
{provide: LocationStrategy, useClass: HashLocationStrategy}
]);
In this case, when you refresh the page, it will be displayed again (but you will have a # in your address).
This link could help you as well: When I refresh my website I get a 404. This is with Angular2 and firebase.
Hope it helps you,
Thierry
I had the same problem. My Angular application is running on a Windows server.
I solved this problem by making a web.config file in the root directory.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="AngularJS" 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="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Perhaps you can do it while registering your root with RouterModule. You can pass a second object with property useHash:true like the below:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { ROUTES } from './app.routes';
#NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
RouterModule.forRoot(ROUTES ,{ useHash: true }),],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
For people reading this that use Angular 2 rc4 or later, it appears LocationStrategy has been moved from router to common. You'll have to import it from there.
Also note the curly brackets around the 'provide' line.
main.ts
// Imports for loading & configuring the in-memory web api
import { XHRBackend } from '#angular/http';
// The usual bootstrapping imports
import { bootstrap } from '#angular/platform-browser-dynamic';
import { HTTP_PROVIDERS } from '#angular/http';
import { AppComponent } from './app.component';
import { APP_ROUTER_PROVIDERS } from './app.routes';
import { Location, LocationStrategy, HashLocationStrategy} from '#angular/common';
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS,
HTTP_PROVIDERS,
{provide: LocationStrategy, useClass: HashLocationStrategy}
]);
If you're running Angular 2 through ASP.NET Core 1 in Visual Studio 2015, you might find this solution from Jürgen Gutsch helpful. He describes it in a blog post. It was the best solution for me. Place the C# code provided below in your Startup.cs public void Configure() just before app.UseStaticFiles();
app.Use( async ( context, next ) => {
await next();
if( context.Response.StatusCode == 404 && !Path.HasExtension( context.Request.Path.Value ) ) {
context.Request.Path = "/index.html";
await next();
}
});

Angular2 without hash in the url

Now, my website's url looks like this because I'm using the approach described here
http://localhost:4200/#/cadastro
Is it possible to remove the hash in the url and not get the 404 error?
EDIT: Router Module added
const appRoutes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'cadastro', component: CadastroNoivosComponent },
{ path: '**', component: HomeComponent }
];
export const routing = RouterModule.forRoot(appRoutes);
If you are using Angular final, the reasons to the hash could be:
RouterModule.forRoot(yourRoutesHere, { useHash: true })
So by removing that could help.
RouterModule.forRoot(yourRoutesHere)
Alternatively if you in your providers (in NgModule) have used:
{provide: LocationStrategy, useClass: HashLocationStrategy}
just remove that.
EDIT, if you need LocationStrategy, try changing HashLocationStrategy to PathLocationStrategy:
{provide: LocationStrategy, useClass: PathLocationStrategy}
More about LocationStrategy here
Now that I have seen your routes as well regarding your 404 issue, you could try changing the following
{ path: '**', component: HomeComponent }
to:
{ path: '**', redirectTo: '', pathMatch: 'full' }
More about routing here
Also check that in your index.html you have set the basehref like so:
<base href="/">
If you use PathLocationStrategy as describe here you can remove the hash in the URL.
But getting rid of 404 error needs some server side tweak. A quick and easy way is to configure your server to load the home page when any URL of the form http://yourhost/* is requested.
Create a .htaccess file Paste the following Code And Upload on your prod Server.
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

Yii2 Advance Application Remove '/web' and 'index.php' in frontend and backend

I referred the below given link
Yii2 htaccess - How to hide frontend/web and backend/web COMPLETELY
Remove index.php from url after removing web folder from frontend and backend in yii2
but, i did't get the output
show below URL
localhost/yii2advance/backend/web/index.php?r=site%2Flogin
localhost/yii2advance/frontend/web/index.php?r=site%2Flogin
in above url i remove /web/index.php in both frontend and backend
I get URL like
localhost/yii2advance/backend/site/login
localhost/yii2advance/frontend/site/login
1- put this code in .htaccess flie in yii2advance folder (main folder of project)
# prevent directory listings
Options -Indexes
IndexIgnore */*
# follow symbolic links
Options FollowSymlinks
RewriteEngine on
RewriteRule ^admin(/.+)?$ backend/web/$1 [L,PT]
RewriteRule ^(.+)?$ frontend/web/$1
above code convert
'localhost/yii2advance/frontend/web/index.php'
to
'localhost/yii2advance/'
and it convert
'localhost/yii2advance/backend/web/index.php'
to
'localhost/yii2advance/admin'
2- add this code to frontend/web/.htaccess and backend/web/.htaccess file:
RewriteEngine on
# If a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Otherwise forward the request to index.php
RewriteRule . index.php
3- in backend/config/main.php put this codes:
'homeUrl' => '/yii2advance/admin',
'components' => [
'request' => [
'baseUrl' => '/yii2advance/admin', // localhost/yii2advance/admin
],
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [],
],
4- in frontend/config/main.php put this codes:
'homeUrl' => '/yii2advance',
'components' => [
'request' => [
'baseUrl' => '/yii2advance', // localhost/yii2advance
],
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [],
],
Create a ".htaccess" file in the "web" directory with:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
My pull request was accepted about this. It will be in the 2.0.19 version.

Webpack dev server configuration refuse to work with full path to index

Hello I am trying to understand why does webpack dev server refuse to work with full path to my index.js. (I am using webpack with babel to build reactJS.)
At the moment my webpack.config is located in the same directory as my index.js file and due to that the declaration of the entry point of my index.js is just "./index". Here is how my webpack.config looks like:
module.exports = {
devtool: 'inline-source-map',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
include: __dirname
}]
}};
With this configuration my project is build by babel and works just fine on the server!
My problem comes when I tried to specify a full path of my index.js entry point. I need that because I want to externalize the webpack and it's configuration from my FE code. To be sure that it will work I first tried not to rely that webpack.config and index.js are in the same directory but to specify the path of the index as full path name:
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'D:/projects/myProject/index'
]
With this config babel seem to be able to navigate to the index.js and start compiling it, but it does encounter an unexpected (for me) error during the parse:
ERROR in D:/projects/myProject/index.js
Module parse failed: D:/projects/myProject/index.js Line 1: Unexpected token
You may need an appropriate loader to handle this file type.
| import 'babel-core/polyfill';
|
| import React from 'react';
# multi main
What do I miss, why webpack makes difference between relatively configured index.js and full path one?
(I made sure that the full path is correct)
Thanks!
After a bit annoying investigation it appeared that my problem is specifying the Windows drives in uppercase. For some reason it appear that the index.js location full path should start with lowercase drive letter!
Hopefully this experience may be helpful to others.
Try using:
d:/Folder1/folder2/index.js
instead of
D:/Folder1/folder2/index.js