Angular调用Steam API出现CORS跨域请求被阻止错误
开发Angular站点时需要调用Steam API获取指定游戏的玩家统计数据,直接在浏览器地址栏访问对应Steam API接口可正常展示返回的JSON数据,但在Angular代码中发起请求时触发异常。
相关代码
data.service.ts
import { HttpClient } from '@angular/common/http'; export class DataService { constructor(private http: HttpClient) { } GetUser() { return this.http.get('https://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v0002/?appid=252490&key=IREMOVEDMYAPIKEYOBVIOUSLY&steamid=IALSOREMOVEDTHESTEAMID').subscribe(data=>{ console.log(data)}) } }
app-search.component.ts
import { Component, OnInit } from '@angular/core'; import { DataService } from '../data.service'; export class AppSearchComponent implements OnInit { constructor(private data: DataService) { } ngOnInit(): void { this.data.GetUser(); } }
报错信息
浏览器控制台首先抛出跨域拦截错误:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at 对应Steam API链接(链接过长已省略). (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.
后续抛出HTTP错误对象:
ERROR Object { headers: {…}, status: 0, statusText: "Unknown Error", url: "对应Steam API链接", ok: false, name: "HttpErrorResponse", message: "HttpFailure response for 对应Steam API链接: 0 Unknown Error", error: error }
已完成的排查验证:
- 调用公开测试接口
https://reqres.in/api/users可正常返回数据,仅调用Steam API时触发CORS错误 - 项目本地通过
ng serve命令在localhost环境运行,申请Steam API Key时平台要求填写绑定域名,不确定填写localhost是否符合规则 - 项目已部署到Firebase平台,使用Firebase分配的站点域名访问时,本地、线上环境均出现相同的跨域报错
Steam官方Web API默认不会给浏览器端发起的跨域请求返回Access-Control-Allow-Origin响应头,和你API Key绑定的域名是localhost还是线上域名没有任何关系,哪怕域名填写完全正确也会触发跨域拦截。
直接在浏览器地址栏访问接口能正常拿到数据,是因为地址栏发起的请求不受浏览器同源策略限制,同源策略仅对页面内脚本发起的异步请求生效。
不要在Angular前端代码里直接请求Steam API,通过代理/服务端中转的方式发起请求即可,分两个场景处理:
- 本地开发阶段:配置Angular内置代理转发请求,避开浏览器跨域限制。在项目根目录新建
proxy.conf.json文件,写入如下配置:
{ "/steam-api": { "target": "https://api.steampowered.com", "secure": true, "changeOrigin": true, "pathRewrite": { "^/steam-api": "" } } }
修改angular.json中serve节点的配置,将proxyConfig字段指向刚才创建的proxy.conf.json文件,重启ng serve后生效。前端代码里把Steam API的请求地址替换为/steam-api/ISteamUserStats/GetUserStatsForGame/v0002/?appid=252490&key=你的APIKey&steamid=目标SteamID即可正常请求。
- 线上部署阶段:你当前使用Firebase部署,可以直接配置Firebase Hosting的重写规则做反向代理,也可以编写简单的Firebase Cloud Functions接口:前端把请求参数传给自己的云函数,由云函数在服务端发起对Steam API的请求,拿到结果后再返回给前端。服务端发起的HTTP请求不受浏览器同源策略限制,可以正常获取返回数据。
额外提醒:不要把Steam API Key硬编码在前端代码中,哪怕配置了代理也不行。前端所有资源用户都可以通过浏览器开发者工具查看,Key泄露后被恶意调用很容易被Steam官方封禁,所有涉及API Key的逻辑必须放在服务端处理。
内容的提问来源于stack exchange,提问作者21sag2

