如何避免单页应用程序中的 CORS 预检请求?

Mar*_*per 8 architecture amazon-web-services cors single-page-application

我想构建一个单页应用程序(SPA),并在后端 API(REST)和前端资产(静态 vue.js 代码)分离期间注意到以下问题:

当从 API 后端以外的其他域提供 index.html 时,大多数 POST/PUT 请求都会触发 CORS 预检请求。

我做了一些研究,发现博客文章 [1][2] 讨论了这个问题 - 没有给出实际的解决方案。某些标头(例如,授权标头和具有application/json值的 Content-Type 标头)不允许作为 cors-safelisted-request-header。因此,POST/PUT 请求会触发 CORS 预检请求。这是不可接受的,因为它增加了大量的延迟。

问题

如果两个域都属于同一实体,是否可以避免这些预检请求?

研究

我做了一些关于如何避免前端和后端之间的 CORS 请求的研究。该解决方案需要从与 REST API 后端相同的域提供 index.html 文件(请参阅下面的示例)。我想知道不使用单独的域是否是避免 SPA 的 CORS 请求的唯一解决方案。

场景(示例)

  • 单页应用程序(SPA);前端和后端层
  • 托管在AWS云中
  • 第 1 层:具有 S3 存储桶源的 CloudFront CDN - 在static.example.com上提供静态资产(Vue.js 前端)
  • 第 2 层:具有 ECS 集成的负载均衡器,运行 node.js 容器来托管example.com上的 (REST) 后端
  • 第 1 层和第 2 层之间的通信使用 HTTPS 协议和 REST 范例。
  • index.html 由第 2 层提供服务,客户使用example.com打开 web 应用程序。
  • index.html 通过指向同一域 ( example.com ) 来引用 API。它通过指向 CDN ( static.example.com ) 来引用静态 vue 资产。
  • SPA 由两部分组成:a)公共资产(.js 文件、.css 文件等)和 b)index.html 文件。后一个容器由同一组后端容器提供服务,这些容器也托管 REST API。

参考

[1] https://www.freecodecamp.org/news/the-terrible-performance-cost-of-cors-api-on-the-single-page-application-spa-6fcf71e50147/
[2] https:// developer.akamai.com/blog/2015/08/17/solving-options-performance-issue-spas

Ana*_*azy 9

如何避免单页应用程序中的 CORS 预检请求?

首先,您不能“避免”标准中的某些内容。其次,这个问题表述有误,因为 SPA 本身可以使用或不使用 CORS。这完全取决于您的设置/设计。如果您想避免预检,请不要从其他来源请求资源。

如果两个域都归同一个实体所有,是否可以避免这些预检请求?

不。

站点所有权与 CORS 无关。跨域资源共享意味着您要在不同的之间共享资源。不一定在不同域之间。Origin 既不是实体也不是所有者。Origin 只是 URL 的一部分。

最好的解决方案是完全避免引入 CORS 问题并始终坚持同源。您认为应该将后端 API 与具有不同来源的前端资产分开的假设是不正确的。

在您的设置中引入多个源和域会增加更多的问题,而不是它解决的问题。理想情况下,您的整个设置应该隐藏在连接客户端之外,并简化为单个域和源。

你想要的设置

                     -> static file server
CDN -> Load balancer -> api server
                     -> api server
                     -> ...
Run Code Online (Sandbox Code Playgroud)

示例配置

使用您的负载均衡器及其 ACL 规则。告诉它把所有流量路由到它应该去的地方。我将使用haproxy作为示例,因为这就是我使用的,并且因为据我所知,这在软件负载平衡解决方案方面几乎是行业标准。

这不是整个配置,只是与路由流量相关的部分。

                     -> static file server
CDN -> Load balancer -> api server
                     -> api server
                     -> ...
Run Code Online (Sandbox Code Playgroud)


mbu*_*ann 4

那里没有太多选择。

最简单的解决方案是从与 API 相同的域提供 html 和资产。

第二个选项是仅使用 cors-safelisted-request-header 标头。

我注意到的是:

可以用标题Content-Type替换标题Accept。这个标题没问题。

如果您正在执行 XHR 请求,则可以省略Authentication标头,而是通过将withCredentialsXHR 请求的字段设置为 true 来自动添加身份验证信息。VanillaJS 示例:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.example.org/api/whatever', true);
xhr.withCredentials = true;
xhr.send();
Run Code Online (Sandbox Code Playgroud)

如果您使用任何其他 XHR 客户端,请查阅文档是否可以设置该选项。

另一种选择是使用 cookie 和服务器端会话进行身份验证。当您使用 AWS 时,AWS Cognito 可能是一个选择。

如果正在使用的更多标头不是列入安全列表的 CORS 标头,则必须删除它们。

  • 我查了一下,没有比 MDN 写得更好的了:`XMLHttpRequest.withCredentials 属性是一个布尔值,指示是否应使用 cookie、授权标头或 TLS 客户端证书等凭据发出跨站点访问控制请求。设置 withCredentials 对同站点请求没有影响。请参阅:https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials Cookie 似乎是安全的选择。不过,您仍然需要获得 API 域的授权。 (2认同)