[英]Angular Universal does not wait for api/http request before render
我有一個全新的 angular 通用項目,它似乎偽裝了所有 HTML(這很好)。 但是,我正在嘗試對我的 .NET 服務器進行 API 調用,這是一個帶有天氣預報 API 的標准 API 構建。
API 調用並且它工作得很好,但它只發生在我的 web 應用程序從預渲染切換到 csr 之后。 參見示例 1。
示例 1
如果我在頁面上禁用 javascript 這就是我得到的
這是 HTML 代碼
<div style="padding: 5rem">
<h1>TEST</h1>
<h2>{{ this.SampleMessage }}</h2>
<div *ngFor="let product of weather$ | async">
<p>{{ this.product.summary }}</p>
</div>
</div>
應用程序組件.ts
import { AppService } from './app.service';
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
title = 'ModernaMediaAngular';
text:string = "test"
weather$: Observable<any>;
SampleMessage="Example of Angular Async Pipe";
constructor(private as: AppService, ) {}
async ngOnInit() {
await this.getWeatherAsyncPipe();
//non async
this.as.getWeather().subscribe( res =>
{
this.text = res[0].date;
console.log("got resolution");
console.log(res);
console.log(this.text);
}
);
}
public async getWeatherAsyncPipe() {
this.SampleMessage="Example of Angular Async Pipe";
this.weather$ = await this.as.getWeatherAsync();
console.log(this.weather$);
}
}
應用程序服務.ts
import { environment } from './../environments/environment';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AppService {
public waeatherUrl = environment.url + '/api/weatherForecast/get'
constructor(private http: HttpClient) { }
getWeather() : Observable<object> {
const headers = new HttpHeaders(
{'Content-Type': 'application/json',
'Access-Control-Allow-Origin' : 'http://localhost:4200'
}
);
var x = this.http.get(this.waeatherUrl, {headers: headers}).pipe();
console.log(x);
return x;
}
public getWeatherAsync():Observable<any> {
return this.http.get<any[]>(this.waeatherUrl);
}
}
應用程序模塊.ts
import { BrowserStateInterceptor } from './interceptors/browserstate.interceptor';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { TransferHttpCacheModule } from '@nguniversal/common'
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
TransferHttpCacheModule,
AppRoutingModule,
HttpClientModule,
],
bootstrap: [AppComponent]
})
export class AppModule {}
應用程序服務器模塊
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 {}
主.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
document.addEventListener('DOMContentLoaded', () => {
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
console.log("DOMCONTENTLOADED");
});
每當預渲染嘗試從 API 獲取時,我也會得到我認為是 cors 的錯誤。
chunk {main} main.js, main.js.map (main) 66.3 kB [initial] [rendered]
chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 141 kB [initial] [rendered]
chunk {runtime} runtime.js, runtime.js.map (runtime) 6.15 kB [entry] [rendered]
chunk {styles} styles.css, styles.css.map (styles) 118 bytes [initial] [rendered]
chunk {vendor} vendor.js, vendor.js.map (vendor) 2.8 MB [initial] [rendered]
Date: 2021-03-15T14:26:38.903Z - Hash: a20337e49cf8941fcbf6 - Time: 12492ms
Hash: af451acd21594faf190e
Time: 19059ms
Built at: 2021-03-15 15:26:41
Asset Size Chunks Chunk Names
main.js 6.44 MiB main [emitted] [big] main
main.js.map 6.99 MiB main [emitted] [dev] main
Entrypoint main [big] = main.js main.js.map
chunk {main} main.js, main.js.map (main) 6.08 MiB [entry] [rendered]
Compiled successfully.
** Angular Universal Live Development Server is listening on http://localhost:4200, open your browser on http://localhost:4200 **
Observable {
_isScalar: false,
source: Observable {
_isScalar: false,
source: Observable {
_isScalar: false,
source: [Observable],
operator: [MergeMapOperator]
},
operator: FilterOperator { predicate: [Function], thisArg: undefined }
},
operator: MapOperator { project: [Function], thisArg: undefined }
}
Observable {
_isScalar: false,
source: Observable {
_isScalar: false,
source: Observable {
_isScalar: false,
source: [Observable],
operator: [MergeMapOperator]
},
operator: FilterOperator { predicate: [Function], thisArg: undefined }
},
operator: MapOperator { project: [Function], thisArg: undefined }
}
ERROR HttpErrorResponse {
headers: HttpHeaders {
normalizedNames: Map {},
lazyUpdate: null,
headers: Map {}
},
status: 0,
statusText: 'Unknown Error',
url: 'https://localhost:5001/api/weatherForecast/get',
ok: false,
name: 'HttpErrorResponse',
message: 'Http failure response for https://localhost:5001/api/weatherForecast/get: 0 Unknown Error',
error: ProgressEvent {
type: 'error',
target: XMLHttpRequest {
onloadstart: null,
onprogress: null,
onabort: null,
onerror: null,
onload: null,
ontimeout: null,
onloadend: null,
_listeners: [Object],
onreadystatechange: null,
_anonymous: undefined,
readyState: 4,
response: null,
responseText: '',
responseType: 'text',
responseURL: '',
status: 0,
statusText: '',
timeout: 0,
upload: [XMLHttpRequestUpload],
_method: 'GET',
_url: [Url],
_sync: false,
_headers: [Object],
_loweredHeaders: [Object],
_mimeOverride: null,
_request: null,
_response: null,
_responseParts: null,
_responseHeaders: null,
_aborting: null,
_error: null,
_loadedBytes: 0,
_totalBytes: 0,
_lengthComputable: false
},
currentTarget: XMLHttpRequest {
onloadstart: null,
onprogress: null,
onabort: null,
onerror: null,
onload: null,
ontimeout: null,
onloadend: null,
_listeners: [Object],
onreadystatechange: null,
_anonymous: undefined,
readyState: 4,
response: null,
responseText: '',
responseType: 'text',
responseURL: '',
status: 0,
statusText: '',
timeout: 0,
upload: [XMLHttpRequestUpload],
_method: 'GET',
_url: [Url],
_sync: false,
_headers: [Object],
_loweredHeaders: [Object],
_mimeOverride: null,
_request: null,
_response: null,
_responseParts: null,
_responseHeaders: null,
_aborting: null,
_error: null,
_loadedBytes: 0,
_totalBytes: 0,
_lengthComputable: false
},
lengthComputable: false,
loaded: 0,
total: 0
}
}
ERROR HttpErrorResponse {
headers: HttpHeaders {
normalizedNames: Map {},
lazyUpdate: null,
headers: Map {}
},
status: 0,
statusText: 'Unknown Error',
url: 'https://localhost:5001/api/weatherForecast/get',
ok: false,
name: 'HttpErrorResponse',
message: 'Http failure response for https://localhost:5001/api/weatherForecast/get: 0 Unknown Error',
error: ProgressEvent {
type: 'error',
target: XMLHttpRequest {
onloadstart: null,
onprogress: null,
onabort: null,
onerror: null,
onload: null,
ontimeout: null,
onloadend: null,
_listeners: [Object],
onreadystatechange: null,
_anonymous: undefined,
readyState: 4,
response: null,
responseText: '',
responseType: 'text',
responseURL: '',
status: 0,
statusText: '',
timeout: 0,
upload: [XMLHttpRequestUpload],
_method: 'GET',
_url: [Url],
_sync: false,
_headers: [Object],
_loweredHeaders: [Object],
_mimeOverride: null,
_request: null,
_response: null,
_responseParts: null,
_responseHeaders: null,
_aborting: null,
_error: null,
_loadedBytes: 0,
_totalBytes: 0,
_lengthComputable: false
},
currentTarget: XMLHttpRequest {
onloadstart: null,
onprogress: null,
onabort: null,
onerror: null,
onload: null,
ontimeout: null,
onloadend: null,
_listeners: [Object],
onreadystatechange: null,
_anonymous: undefined,
readyState: 4,
response: null,
responseText: '',
responseType: 'text',
responseURL: '',
status: 0,
statusText: '',
timeout: 0,
upload: [XMLHttpRequestUpload],
_method: 'GET',
_url: [Url],
_sync: false,
_headers: [Object],
_loweredHeaders: [Object],
_mimeOverride: null,
_request: null,
_response: null,
_responseParts: null,
_responseHeaders: null,
_aborting: null,
_error: null,
_loadedBytes: 0,
_totalBytes: 0,
_lengthComputable: false
},
lengthComputable: false,
loaded: 0,
total: 0
}
}
但控制台中沒有錯誤:
在我的 .NET 5 項目的startup.cs中,我配置了 cors:
public void ConfigureServices(IServiceCollection services) {
services.AddControllers();
services.AddSwaggerGen(c => {
c.SwaggerDoc("v1", new OpenApiInfo { Title = "ModernaMediaDotNet", Version = "v1" });
});
services.AddCors();
}
並在 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseRouting();
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed(origin => true) // allow any origin
);
我曾經在我們的測試環境中遇到過同樣的問題,這是由於我們使用的是自簽名證書,這是節點不喜歡的。
我們最終在server.ts
中添加了以下行,以便節點禁用 TLS 驗證。
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
注意這是不安全的( 文檔),你不應該在產品中使用它(你應該有有效的證書)。
另一種選擇是僅在服務器端進行 http 調用,您可以使用HttpInterceptor
來實現
您的應用程序可能需要將 API 調用包裝在區域宏任務中。
@bespunky/angular-zen
RouterXModule
( .forRoot()
或.forChild()
根據您的模塊)。RouteAware
class。this.resolveInMacroTask()
中包裝你的 observable。您可以手動完成,但
RouteAware
會處理所有事情並為您提供額外的好處。
我遇到了同樣的問題,在你的路由模塊中使用一個解析器,它會解決它,祝你編碼愉快!
constructor(
private activatedRoute: ActivatedRoute,
) {
this.activatedRoute.data.subscribe(({ animes }) => {
this.animeList = animes;
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.