Dot-Net
Angular Universal 在渲染之前不會等待 api/http 請求
我有一個全新的 Angular 通用項目,它似乎偽裝了所有的 HTML(這很好)。但是,我正在嘗試對我的 .NET 伺服器進行 API 呼叫,該伺服器是使用 weatherforecast API 建構的標準 API。
API呼叫並且效果很好,但它只發生在我的網路應用程序從預渲染切換到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>app.component.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); } }app.module.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 {}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 {}main.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(); }並在公共 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


