John Marquez
John Marquez

Reputation: 635

How can I construct a link that goes to one of my Angular app routes?

I have an app running at "www.example.com", which is sitting along side some static html pages. I need to provide a 'registration' link that goes to www.example.com/guest_register. This works locally, but not on the server.

Background:

When I run locally, I can create a link to http://localhost:4200/guest?token=asdf&user=username that works fine to register a new user. Out on the server, a link to http://www.example.com/guest?token=asdf&user=username gives a 404 error....an link to http://www.example.com/#/guest?token=asdf&user=username sends me to my index.html. I tried adding the '#' on a hunch, but I'm not sure what the real difference is.

The public_html directory of the server looks like:

index.html //a static page main.html // my actual Angular app styles.-----.js scripts.-----.js runtime.----.js polyfills.----.js main.-----.js 3rdpartylicenses.txt assets/

I serve up index.html for the general public, and then link into main.html as needed to log in registered users. Locally, the browser address bar switches from file://..index.html to localhost:4200 when I link into my app. On the server, the address bar reloads from www.example.com to www.example.com.

Here is my route map in app.module.ts:

const appRoutes: Routes = [
  { path: '', component: WizardComponent, canActivate: [AuthGuard] },
  { path: 'login', component: LoginComponent },
  { path: 'guest', component: GuestComponent },
  { path: 'admin', component: AdminComponent, canActivate: [AdminGuard] },
  { path: '**', redirectTo: '' }
];
.
.
@NgModule({
  declarations: [
.
.
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    HttpClientModule,
    RouterModule.forRoot(appRoutes),
.
.

Nothing too fancy. So, what is keeping me from directly appending /guest to the end of the URL while on the server, but not locally?

EDIT: It seems my app is falling back to index.html when it should be falling back to main.html (my angular app) when an unrecognized URL is requested, according to these official docs:

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

My .htaccess already has a few mysterious lines in it that I only understand well enough to know they work to redirect all users other than my IP to maintenance.html when maintenance.enable exists:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REMOTE_ADDR} !^MY\.IP\.ADD\.RESS
RewriteCond %{DOCUMENT_ROOT}/maintenance.html -f
RewriteCond %{DOCUMENT_ROOT}/maintenance.enable -f
RewriteCond %{REQUEST_URI} !^/maintenance\.html$ [NC]
RewriteCond %{REQUEST_URI} !\.(jpe?g?|png|gif) [NC]
#RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^(.*)$ /maintenance.html [R=302,L]
</IfModule>

How do I integrate the suggestion on the official docs into my existing .htaccess file?

Upvotes: 1

Views: 778

Answers (1)

sinanspd
sinanspd

Reputation: 2734

I will elaborate on my comment a little bit further. When you compile your Angular project, it collapses everything into a single file, this is normally what is called a single page application Historically, this is very different from how the web servers were setup.

The part after the first / normally translates into a file. So in the case of

www.example.com/guest_register

An out-of-the-box server looks for guest_register.html in the www folder. In the case of single page applications, this precondition is not met. You don't have a file called guest_register.html, as a result the server responds with 404.

What angular router does is, take the original request and figure out what "page" to serve you.

In a production environment, the only entry point to you application is index.html, thus you need to explicitly tell the server to redirect any 404 to index.html (fallback is the technical term)

This is not a problem when you run it locally through

ng serve

because this command starts a local server that is configured with this behavior

The details of how to configure is laid out here

Copying the highlights below in case the link goes down (which seems to be happening to the angular page often lately)

Apache:

add to .htaccess

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:

try_files $uri $uri/ /index.html;

Firebase:

Add to rewrite rules

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

Hope it helps

Upvotes: 1

Related Questions