如何解决Angular Universal 在渲染前不等待 api/http 请求
我有一个全新的 angular 通用项目,它似乎伪装了所有的 HTML(这很好)。 但是,我正在尝试对我的 .NET 服务器进行 API 调用,该服务器是使用 weatherforecast API 构建的标准 API。
API 调用并且运行良好,但仅在我的 Web 应用程序从预渲染切换到 csr 后才会发生。见例一。
示例 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$);
}
}
app.service.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,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: '',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,lengthComputable: false,loaded: 0,total: 0
}
}
ERROR HttpErrorResponse {
headers: HttpHeaders {
normalizedNames: Map {},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();
}
在公共无效配置(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';
注意这是不安全的 (documentation),您不应在生产中使用它(您应该拥有有效证书)。
另一种选择是仅在服务器端进行 http 调用,您可以使用 HttpInterceptor
您的应用可能需要将 API 调用包装在区域宏任务中。
- npm install
@bespunky/angular-zen
- 根据您的模块导入
RouterXModule
(.forRoot()
或.forChild()
)。 - 让您的组件/服务扩展
RouteAware
类。 - 将您的 observable 封装在对
this.resolveInMacroTask()
的调用中。
您可以手动完成,但 RouteAware
会处理一切并且会给您带来额外的好处。
更多
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。