【问题标题】:Angular SSR Refresh/Load Page Pending Api CallAngular SSR 刷新/加载页面挂起的 API 调用
【发布时间】:2020-05-05 10:51:20
【问题描述】:

我正在使用 Angular 9 .net 核心 spa 应用程序。在带有 api 调用的页面上,应用程序卡住(在 Chrome 中的“网络”选项卡上挂起)并返回(失败)net:ERR_EMPTY_RESPONSE

主页工作正常,在 ng-init 事件上使用 api,其他没有 api 调用的页面工作正常,我可以在这些页面之间来回跳转而不会出现问题。只是依赖于 api 调用的其他页面会出现问题。

web.config 是空的,因为我只是在 VS 2019 中构建并发布。在 localhost:4200 上一切正常,但在端口 localhost:4000 (ssr) 上出现问题

请参阅下面的代码 - 我在一个非常简单的 api 调用中创建的示例页面,其中数据正确地传回了组件。当我尝试使用 ng serve 的 url "http://localhost:4200/food-facts3/3" 可以正常工作,但是当我尝试 "http://localhost:4000/food-facts3/3" 时,它会卡在 Chrome 中 - 使用 ssr。 url "http://localhost:4000/food-facts3/3" 等待大约 3 分钟,然后返回(失败的)net:ERR_EMPTY_RESPONSE。 iisnode npm 命令提示显示错误-“无法读取未定义的 PendingInterceptorService.Intercept 的属性管道”

@Injectable()
 export class HttpConfigInterceptor implements HttpInterceptor, OnInit {
constructor(@Inject(PLATFORM_ID) private platformId: any, public errorDialogService: ErrorDialogService) { }

ngOnInit() {
}

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

   if (isPlatformBrowser(this.platformId)) {
        const token = localStorage.getItem('Token');

        if (token) {
            request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + token) });
        }
    }
        request = request.clone({ headers: request.headers.set('Accept', 'application/json') });

        return next.handle(request); //This is to do more but just trying to isolate the bug

    }

}

应用路由

  {
    path: 'food-facts3/:id',
    component: Fact3Component,
    resolve: { fact: FactResolver }
  }

事实解析器

export class FactResolver implements Resolve<Fact> {

constructor(private srv: FactApiRestService, @Inject(PLATFORM_ID) private platformId, private transferState: TransferState) { }

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Fact> {

    const factId = route.params['id'].toString();

    const Key = makeStateKey<Fact>('fact-' + factId);

    if (this.transferState.hasKey(Key)) {

        const data = this.transferState.get<Fact>(Key, null);

        this.transferState.remove(Key);

        return of(data);
    }
    else {
        return this.srv.getFact(factId)
            .pipe(
                first(),
                tap(data => {
                    if (isPlatformServer(this.platformId)) {
                        this.transferState.set(Key, data);
                    }
                })
            );
    }
}

}

Fact Api 休息服务

const apiUrl = environment.apiRestUrl + '/fact';

@Injectable({
providedIn: 'root'
})
export class FactApiRestService {
fact: Fact;
factList: Fact[];

constructor(private http: HttpClient) {
}

getFact(factId: number){
  return this.http.get<Fact>(apiUrl + '/factbyId/' + factId);
}

}

Fact3组件

export class Fact3Component implements OnInit {
fact: Fact;
constructor(private route: ActivatedRoute, private srv: FactApiRestService, private title: Title, 
private meta: Meta) { }

ngOnInit() {
  this.fact = this.route.snapshot.data['fact'];
  this.title.setTitle(this.fact.Name);
  this.meta.addTag({ name: 'description', content: this.fact.FactTypeName });
}

}

Web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
  <system.webServer>
  <handlers>
    <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" 
  />
  </handlers>
  <aspNetCore processPath=".\MyApp.WebUI.exe" stdoutLogEnabled="false" stdoutLogFile=".\stdout" 
   hostingModel="inprocess" />
  </system.webServer>
 </location>
</configuration>

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';
import { FlexLayoutServerModule } from '@angular/flex-layout/server';

@NgModule({
  imports: [
    AppModule,
    ServerModule,
    FlexLayoutServerModule,
    ServerTransferStateModule
  ],
  bootstrap: [AppComponent],
})
export class AppServerModule { }

app.module

@NgModule({
  imports: [
    MatIconModule,
    MatCardModule,
    MatButtonModule,
    MatProgressBarModule,
    MatTooltipModule,
    MatRadioModule,
    MatExpansionModule,
    ToastrModule.forRoot({ positionClass: 'toast-top-center' }),
    FlexLayoutModule,
    MaterialModule,
    FormsModule,
    FurySharedModule,
    AllthemealModule,
    // Angular Core Module // Don't remove!
    BrowserModule.withServerTransition({ appId: 'serverApp' }),
    BrowserTransferStateModule,
    BrowserAnimationsModule,
    HttpClientModule,
    HttpClientJsonpModule,
    CommonModule,
    // Fury Core Modules
    AppRoutingModule,

    // Layout Module (Sidenav, Toolbar, Quickpanel, Content)
    LayoutModule,

    // Displays Loading Bar when a Route Request or HTTP Request is pending
    PendingInterceptorModule,

    // Register a Service Worker (optional)
    // ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })
  ],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  providers: [
    FactApiRestService,
    FactResolver,
    { provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true },
  ]
})
export class AppModule {
}

【问题讨论】:

  • 如果你没有返回任何东西! isPlatformBrowser 在你的拦截器中..?
  • 是的,感谢 MikeOne 更新了代码

标签: angular server-side-rendering angular-universal


【解决方案1】:

我忘了返回 if !迈克指出的 isPlatformBrowser 代码已更新并且现在可以正常工作,感谢迈克

【讨论】:

    猜你喜欢
    • 2019-06-07
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多