【发布时间】:2021-10-03 13:58:50
【问题描述】:
在使用 AngularJS 一段时间后,我开始学习 Angular 2+,并且一直在使用 Angular Universal 进行 SSR 尝试并一路学习。
但是,我在 ngOnInit 中的 API 请求中遇到了这个 CORS 问题,其中一个视图加载了有关所选项目的其他详细信息。
只有当我从列表页面(通过路由器链接选择硬币的静态列表)导航到特定硬币的详细信息页面时,才会出现 CORS 问题。
在完成这些工作时,我将这两个教程用作指导帖子。
Angular SSR With HttpClient rehydration
任何帮助都将不胜感激,我的前端技能不是很强,而且我对 CORS 也不是很熟悉。
路由器代码片段:
const routes: Routes = [
{ path: '', component: CoinListComponent },
{ path: 'coin/:symbol', component: CoinSnapshotComponent },
];
@NgModule({
imports: [
RouterModule.forRoot(routes, {
initialNavigation: 'enabled',
}),
],
exports: [RouterModule],
})
export class AppRoutingModule {}
列表视图:
<h2>Current Coins</h2>
<ul *ngFor="let coin of coins">
<li>
<div>
<a routerLink="/coin/{{coin.symbol}}"><span>{{coin.name}} - {{coin.symbol}}</span></a>
</div>
</li>
</ul>
硬币细节组件:
interface CoinData {
[key: string]: number;
}
interface CoinDataResponse {
data: {
currency: string;
rates: CoinData;
};
}
@Component({
selector: 'app-coin-snapshot',
templateUrl: './coin-snapshot.component.html',
styleUrls: ['./coin-snapshot.component.scss'],
})
export class CoinSnapshotComponent implements OnInit {
coins = coins;
coin: Coin;
defaultCoin: Coin;
coinData: CoinData | undefined;
constructor(
private route: ActivatedRoute,
private http: CustomHttpClientService
) {
this.defaultCoin = {
symbol: 'DEFAULT',
name: 'DEFAULT',
link: 'DEFAULT',
};
const symbol = this.route.snapshot.paramMap.get('symbol');
this.coin = this.findCoinBySymbol(symbol);
}
ngOnInit(): void {
if (!this.isDefault(this.coin)) {
this.getCoinData(this.coin);
}
}
findCoinBySymbol(symbol: string | null) {
const coin = this.coins.find((coin) => coin.symbol === symbol);
if (!coin) {
return this.defaultCoin;
}
return coin;
}
isDefault(coin: Coin) {
return coin.name === 'DEFAULT' && coin.symbol === 'DEFAULT';
}
getCoinData(coin: Coin) {
this.http.get<CoinDataResponse>(coin.link).subscribe((coin) => {
this.coinData = coin.data.rates;
});
}
}
链接来自的硬币对象:
export interface Coin {
name: string;
symbol: string;
link: string;
}
const coins: Coin[] = [
{
name: 'Bitcoin',
symbol: 'BTC',
link: 'https://api.coinbase.com/v2/exchange-rates?currency=BTC',
},
{
name: 'Ethereum',
symbol: 'ETH',
link: 'https://api.coinbase.com/v2/exchange-rates?currency=ETH',
},
{
name: 'Chainlink',
symbol: 'LINK',
link: 'https://api.coinbase.com/v2/exchange-rates?currency=LINK',
},
];
export default coins;
CustomHttpClient代码(主要来自Angular SSR With HttpClient rehydration文章):
import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
import { HttpParams, HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
import {
StateKey,
makeStateKey,
TransferState,
} from '@angular/platform-browser';
import { isPlatformServer } from '@angular/common';
@Injectable()
export class CustomHttpClientService {
constructor(
private httpClient: HttpClient,
private transferState: TransferState,
@Inject(PLATFORM_ID) private platformId: Object
) {}
get<T>(path: string, params?: HttpParams): Observable<T> {
const transferKey: StateKey<T> = makeStateKey(
`${path}?${params != null ? params.toString() : ''}`
);
if (this.transferState.hasKey(transferKey)) {
return of(this.transferState.get<any>(transferKey, 0)).pipe(
tap(() => this.transferState.remove(transferKey))
);
} else {
return this.httpClient
.get<T>(path, { observe: 'body', responseType: 'json', params: params })
.pipe(
tap((response) => {
if (isPlatformServer(this.platformId)) {
this.transferState.set<T>(transferKey, response);
}
})
);
}
}
}
核心模块:
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { CustomHttpClientService } from 'src/app/core/custom-http-client.service';
import { CookiesInterceptor } from 'src/app/core/cookies.interceptor';
@NgModule({
imports: [HttpClientModule],
providers: [
CustomHttpClientService,
{
provide: HTTP_INTERCEPTORS,
useClass: CookiesInterceptor,
multi: true,
},
],
})
export class CoreModule {}
【问题讨论】:
-
您介意分享
CustomHttpClientService的代码吗? -
@PsyGik 我更新了代码以包含
CustomHttpClientService和与之配套的CoreModule的sn-ps。 -
CORS 主要是后端问题。最有可能发生的是 api.coinbase.com 不允许通过您的 localhost:4200 访问您基本上可以使用 http-proxy-middleware 代理请求或从 counbase 端仔细检查 CORS 设置
标签: angular cors server-side-rendering angular-universal