如何解决 XMLHttpRequest.send 处的 ERROR NetworkError (...dist\fxcore\server\main.js:200768:19)

Ben*_*ito 6 javascript xmlhttprequest node.js angular angular9

我是 Angular 的新手。我刚刚完成了我的 Angular Web 应用程序的开发。当我在生产过程中使用 ng serve 为我的应用程序提供服务时,一切正常。我添加了角度通用。现在,当我运行 npm run dev:ssr 或 npm run build:ssr && npm run serve:ssr 时,我的应用程序将拒绝打开,并在控制台中抛出 NetworkError 响应。我注意到这个错误发生在通过类'constructors(){..}'发送的http请求的次数。我浏览了几个解决方案,但无法了解我做错了什么。我的后端是用 nodejs 和 express 开发的。我会很感激我能得到的任何帮助。这是我总是在控制台中得到的错误响应的完整示例。

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)```
Run Code Online (Sandbox Code Playgroud)

Bin*_*s00 6

我为这个错误苦苦挣扎了好几天,直到我找到这篇关于如何创建相对于绝对拦截器的文章 ,这是链接

https://bcodes.io/blog/post/angular-universal-relative-to-absolute-http-interceptor

  1. 我在 src 文件夹中创建了“universal-relative.interceptor.ts”文件
  2. 将此拦截器代码放入“universal-relative.interceptor.ts”文件中
import { HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Inject, Injectable, Optional } from '@angular/core';
import { REQUEST } from '@nguniversal/express-engine/tokens';
import { Request } from 'express';

// case insensitive check against config and value
const startsWithAny = (arr: string[] = []) => (value = '') => {
    return arr.some(test => value.toLowerCase().startsWith(test.toLowerCase()));
};

// http, https, protocol relative
const isAbsoluteURL = startsWithAny(['http', '//']);

@Injectable()
export class UniversalRelativeInterceptor implements HttpInterceptor {
    constructor(@Optional() @Inject(REQUEST) protected request: Request) {}

    intercept(req: HttpRequest<any>, next: HttpHandler) {
        if (this.request && !isAbsoluteURL(req.url)) {
            const protocolHost = `${this.request.protocol}://${this.request.get(
                'host'
            )}`;
            const pathSeparator = !req.url.startsWith('/') ? '/' : '';
            const url = protocolHost + pathSeparator + req.url;
            const serverRequest = req.clone({ url });
            return next.handle(serverRequest);
        } else {
            return next.handle(req);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 转到您的“app.server.module.ts”文件
  2. 像这样添加你的拦截器
import { NgModule } from '@angular/core';
import {
  ServerModule,
  ServerTransferStateModule,
} from "@angular/platform-server";

import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { UniversalRelativeInterceptor } from 'src/universal-relative.interceptor';
import { HTTP_INTERCEPTORS } from '@angular/common/http';

@NgModule({
  imports: [AppModule, ServerModule, ServerTransferStateModule],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: UniversalRelativeInterceptor,
      multi: true,
    },
  ],
  bootstrap: [AppComponent],
})
export class AppServerModule {}

Run Code Online (Sandbox Code Playgroud)

错误消失了!


Ian*_*mer 5

我仍然得到这个ERROR NetworkError,但我找到了另一种方法来消除这个错误。我认为这个答案是相关的,因为我收到了上面发布的相同错误。如果这可以帮助任何遇到相同服务器错误的人,那就太好了。

OnInit如果重新加载时向服务器发出 api 请求,请isPlatformBrowser在使用ng-universal示例时首先检查。

import { Component, OnInit, PLATFORM_ID, Inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { HttpClient, HttpHeaders } from '@angular/common/http';

export class HomeComponent implements OnInit {

  public testBrowser  : boolean;
  public data         : any;
  
  constructor(private http: HttpClient, @Inject(PLATFORM_ID) platformId: string) {
    this.testBrowser = isPlatformBrowser(platformId);
  }

  ngOnInit() {
    if (this.testBrowser) {
      //avoid server NETWORK error
      this.data = this.http.get('/api');
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

isPlatformBrowser === true在首先检查之前,我尝试从客户端进行服务器调用,但遇到了同样的错误OnInit,这解决了我的问题。希望这可以帮助这个错误。

作为参考,这个答案帮助我解决了这个长期存在的错误。/sf/answers/3282540341/

  • @MihaiMarinescu 我的主要 SEO 是在我的 `app.component.ts` 中设置的,我不使用上面的示例来等待浏览器设置元数据,这并不是首先导致网络错误的原因。这根本不会干扰您的搜索引擎优化。对我来说,网络错误是由于在浏览器准备好处理数据之前尝试获取数据而引起的。你可以查看我的 Github 网站,了解我如何在 Angular nguniversal 应用程序中处理 SEO。 (2认同)

Ian*_*mer 3

我遇到了同样的错误。尝试TransferHttpCacheModule从您的app.module自定义 http 传输拦截器文件中删除并创建您自己的自定义 http 传输拦截器文件。

我创建了一个名为 的文件transfer-state.interceptor.ts,然后将其添加到app.module providers:[]处理此问题。下面的示例将展示我如何连接它。我不确定这是否一定对你有用,但它确实让我的错误消失了。


//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 { }

Run Code Online (Sandbox Code Playgroud)

这是自定义传输状态文件的一个版本,但如果此版本不起作用,可以通过几种方法来执行此操作。


//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);
      }
    }
  }
}

Run Code Online (Sandbox Code Playgroud)

如果你想添加自定义缓存,你可以通过安装来添加memory-cache,但我还没有尝试过。有关更多参考资料,这些文章对我帮助很大,也许它们也可以帮助您。

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

如果没有,您可能需要添加ServerTransferStateModule到您的 app.server.module 文件中。


//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 {}

Run Code Online (Sandbox Code Playgroud)

祝你好运!

  • 我使用了绝对URL,它解决了这个问题。感谢您的贡献。 (2认同)