I am new to Angular. I just finished developing my angular web application. When I use ng serve to serve my application during production, everything works fine. I added angular universal. Now when I run any of npm run dev:ssr or npm run build:ssr && npm run serve:ssr, my application will refuse to open, throwing NetworkError response in the console. I noticed this error occurs for the number of times http requests where sent via class 'constructors(){..}'. I have browsed through several solution but couldn't get a clue of what I'm not doing right. My backend is developed with nodejs and express. I'll appreciate any help I can get. Here is a full example of the error response I always get in the console.
ERROR NetworkError
at XMLHttpRequest.send (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:200768:19)
at Observable._subscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:19025:17)
at Observable._trySubscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:186304:25)
at Observable.subscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:186290:22)
at scheduleTask (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:105897:32)
at Observable._subscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:105959:13)
at Observable._trySubscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:186304:25)
at Observable.subscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:186290:22)
at subscribeToResult (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:196385:23)
at MergeMapSubscriber._innerSub (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:191575:116)```
I am getting the same error. Try to remove TransferHttpCacheModule
from your app.module
and create your own custom http transfer interceptor file.
I made a file called transfer-state.interceptor.ts
and then added it to app.module
providers:[]
to handle this. The examples below will show how I hooked it up. I am not sure if this will definitely work for you but it did make that error go away for me.
//app.module.ts
import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http";
//import {TransferHttpCacheModule } from '@nguniversal/common';
import { AppRoutingModule } from './app-routing/app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './modules/home/home.component';
import { SliderComponent } from './components/slider/slider.component';
import { WindowRefService } from './services/window-ref.service';
//import { TransferHttpInterceptorService } from './services/transfer-http-interceptor.service';
import { TransferStateInterceptor } from './interceptors/transfer-state.interceptor';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
SliderComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
BrowserTransferStateModule,
AppRoutingModule,
HttpClientModule,
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })
],
providers: [
WindowRefService,
{
provide: HTTP_INTERCEPTORS,
useClass: TransferStateInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
This is one version of a custom transfer state file but there are a few ways to do this if this one doesn't work.
//transfer-state.interceptor.ts
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { Inject, Injectable, PLATFORM_ID } from '@angular/core';
import { Observable, of } from 'rxjs';
import { StateKey, TransferState, makeStateKey } from '@angular/platform-browser';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
import { tap } from 'rxjs/operators';
@Injectable()
export class TransferStateInterceptor implements HttpInterceptor {
constructor(
private transferState: TransferState,
@Inject(PLATFORM_ID) private platformId: any,
) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// For this demo application, we will only worry about State Transfer for get requests.
if (request.method !== 'GET') {
return next.handle(request);
}
// Use the request url as the key.
const stateKey: StateKey<string> = makeStateKey<string>(request.url);
// For any http requests made on the server, store the response in State Transfer.
if (isPlatformServer(this.platformId)) {
return next.handle(request).pipe(
tap((event: HttpResponse<any>) => {
this.transferState.set(stateKey, event.body);
})
);
}
// For any http requests made in the browser, first check State Transfer for a
// response corresponding to the request url.
if (isPlatformBrowser(this.platformId)) {
const transferStateResponse = this.transferState.get<any>(stateKey, null);
if (transferStateResponse) {
const response = new HttpResponse({ body: transferStateResponse, status: 200 });
// Remove the response from state transfer, so any future requests to
// the same url go to the network (this avoids us creating an
// implicit/unintentional caching mechanism).
this.transferState.remove(stateKey);
return of(response);
} else {
return next.handle(request);
}
}
}
}
If you want to add custom cache to this you can by installing memory-cache
but I haven't tried that out yet. For more references these articles helped me out a lot and maybe they can help you too.
https://itnext.io/angular-universal-caching-transferstate-96eaaa386198
https://willtaylor.blog/angular-universal-for-angular-developers/
https://bcodes.io/blog/post/angular-universal-relative-to-absolute-http-interceptor
If you haven't you may need to add ServerTransferStateModule
to your app.server.module file.
//app.server.module
import { NgModule } from '@angular/core';
import {
ServerModule,
ServerTransferStateModule
} from "@angular/platform-server";
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [
AppModule,
ServerModule,
ServerTransferStateModule
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With