如何将 CORS 预检缓存应用于整个域
Posted
技术标签:
【中文标题】如何将 CORS 预检缓存应用于整个域【英文标题】:How to apply CORS preflight cache to an entire domain 【发布时间】:2012-08-14 08:10:09 【问题描述】:我正在构建一个使用 CORS 的 REST 应用程序。每个 REST 调用都是不同的,我发现在获取预检 OPTIONS 调用时会有很大的开销。有没有办法缓存和应用预检 OPTIONS 结果,以便对同一域的任何后续调用都使用缓存的响应?
【问题讨论】:
问题附录:如果无法缓存较小范围的预检,那么在 RESTful 应用程序中限制预检请求数量的最佳方法是什么? 反向代理,检查 nginx,将允许您避免 CORS 飞行前惩罚。只需映射 /api -> api.site.com Wikipedia article on CORS 有一个很好的流程图,帮助我了解在什么条件下会进行预检调用(以及如何避免它们)。 【参考方案1】:一种方法是,您可以将所有 API 调用指向与前端相同的域。在前端服务器上设置 nginx 以仅将 API 调用转发到 API 服务器。这将删除所有飞行前呼叫。
【讨论】:
【参考方案2】:尝试使用 xDomain
如果使用 Angular 或 jQuery,我的设置非常简单。在您的应用服务器上,按照以下链接的帮助中的说明添加 proxy.html。在您的“客户端”和中提琴上添加一些引用 js 文件的标签,不再进行预检。这包含在 iframe 中以避免需要进行 cors 检查。
https://github.com/jpillora/xdomain
【讨论】:
【参考方案3】:预检只能应用于请求,不能应用于整个域。我在邮件列表中提出了同样的问题,并且存在安全问题。这是整个线程:http://lists.w3.org/Archives/Public/public-webapps/2012AprJun/0228.html
如果您想限制预检请求的数量,需要考虑一些事项。首先请注意,基于 WebKit/Blink 的浏览器将最大预检缓存设置为 10 分钟:
https://github.com/WebKit/webkit/blob/master/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp https://chromium.googlesource.com/chromium/blink/+/master/Source/core/loader/CrossOriginPreflightResultCache.cpp
(我不确定这是否适用于其他浏览器)。因此,虽然您应该始终设置 Access-Control-Max-Age 标头,但最大值为 10 分钟。
接下来请注意,无法避免对 PUT/DELETE 请求进行预检。因此,更新/删除 API 至少需要每 10 分钟进行一次预检。
在 GET/POST 上,尽可能避免使用自定义标头,因为它们仍会触发预检。如果您的 API 返回 JSON,请注意“application/json”的 Content-Type 也会触发预检。
如果您愿意改变您的 API 的“RESTful”程度,您可以尝试其他一些方法。一种是使用不需要预检的 Content-Type,例如“text/plain”。自定义标头始终触发预检,因此如果您有任何自定义标头,您可以将它们移动到查询参数中。在极端情况下,您可以使用 JSON-RPC 之类的协议,其中所有请求都发送到单个端点。
老实说,由于浏览器的 10 分钟预检缓存限制和 REST 的资源 url,预检缓存相当无用。在长时间运行的应用程序过程中,您几乎无法限制预检。我希望 CORS 规范的作者将来会尝试解决这个问题。
【讨论】:
@uglymunky 我将澄清该部分。预检缓存的密钥基于源/url 对,其中 url 是完整的请求 url。我的意思是,如果您有一个自定义标头,它将始终触发预检,即使是在 GET 请求中也是如此。但是,如果您将该自定义标头移动到查询参数中,则不会对 GET/POST 请求进行预检。 @monsur 晚了一点,但想知道您是否可以建议.. 我目前正在传递一个授权标头(例如“基本 [base64 编码字符串]”)以及我的所有请求API。预检请求主要阻碍了应用程序的性能。如果我要迁移到基于令牌的身份验证系统(将令牌作为 URL 中的 QS 参数),并完全摆脱自定义标头,这是否是避免 GET 和 POST 的可怕 OPTIONS 请求的一种方式(我'我可以有一些用于 PUT 和 DELETE)吗? @adaam 应该可以解决问题。我刚刚在 Firefox 和 Chrome 中完成了一些测试,以更好地理解这种行为,并且可以分享以下内容:如果您的自定义标头存在,浏览器将触发 OPTIONS 请求,除非存在Access-Control-Max-Age
并且完全相同的 URL之前被浏览器看到并且在Access-Control-Max-Age
指定的时间段内,并且有问题的浏览器不会缩短该值(Webkit、Firefox)。如果您摆脱自定义标头并将它们移动到 url,浏览器将不会发送 OPTIONS 请求。胜利!
我喜欢他们刚刚停止回复您的电子邮件的方式。所有这些多余的调用,针对单个边缘情况。
在您的回答中,Content-Type 限制仅在 发送 数据时相关,而不是在接收数据时相关,因此服务器返回任意 content-type 标头没有问题。
以上是关于如何将 CORS 预检缓存应用于整个域的主要内容,如果未能解决你的问题,请参考以下文章