如何将CORS预检缓存应用于整个域


78

我正在构建一个利用CORS的REST应用程序。每个REST调用都是不同的,我发现获取预检OPTIONS调用会产生大量开销。有没有一种方法可以缓存和应用预检OPTIONS结果,以便对同一域的任何后续调用都可以使用缓存的响应?


1
问题附录:如果无法为较小的范围缓存预检,则在RESTful应用程序中限制预检请求数量的最佳方法是什么?
罗伯W

1
反向代理(请查看nginx)将使您避免CORS飞行前罚款。只需映射/ api-> api.site.com
道格拉斯·弗格森

上CORS维基百科的文章有帮我下预检通话将作出什么样的条件理解(因此如何避免它们)一个漂亮的流程图。
特伦顿

Answers:


104

预检只能应用于请求,而不能应用于整个域。我在邮件列表中提出了同样的问题,并且存在安全隐患。这是整个主题: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,请注意Content-Type为“ application / json”也会触发预检。

如果您愿意改变API的“ RESTful”程度,则可以尝试更多方法。一种是使用不需要预检的Content-Type,例如“文本/纯文本”。自定义标题始终会触发预检,因此,如果您有任何自定义标题,则可以将其移至查询参数中。在最末端,您可以使用JSON-RPC之类的协议,其中所有请求都向单个端点发出。

老实说,由于浏览器的预检缓存限制为10分钟,并且REST的资源网址如此,因此预检缓存相当无用。在长期运行的应用程序中,您几乎没有什么可以限制飞行前检查的。我希望CORS规范的作者将来会尝试解决这个问题。


3
@uglymunky我将澄清这一部分。飞行前缓存的密钥基于原始/ URL对,其中URL是完整的请求URL。我的意思是,如果您有一个自定义标头,即使在GET请求上,它也总是会触发预检。但是,如果将该自定义标头移到查询参数中,则GET / POST请求将不会进行预检。
monsur

2
@monsur嗨,参加聚会很晚,但是想知道您是否可以提出建议。.我目前正在将一个带有所有请求的Authorization标头(例如“ Basic [base64编码的字符串]”)传递给我的API。飞行前请求主要阻碍了应用程序的性能。如果我要转到基于令牌的身份验证系统(令牌作为URL中的QS参数),并完全摆脱自定义标头,这是否可以避免对GET和POST的可怕OPTIONS请求(我我可以添加一些PUT和DELETE吗?
adaam

5
@adaam应该可以解决问题。我刚刚在Firefox和Chrome中完成了一些测试,以更好地了解其行为,并且可以分享以下信息:如果存在您的自定义标头,除非Access-Control-Max-Age存在且浏览器看到了完全相同的URL,否则浏览器将触发OPTIONS请求。之前的浏览器,并且它在所指定的期限内,Access-Control-Max-Age并且所涉及的浏览器不会缩短值(Webkit,Firefox)。如果您摆脱了自定义标头,并将其移至url,浏览器将不会发送OPTIONS请求。胜利!
mikegradek 2015年

2
我喜欢他们刚刚停止回复您的电子邮件的方式。对于单个边缘情况,所有这些冗余调用。
Rebs

3
在您的回答中,Content-Type限制仅在发送数据时才相关,而在接收数据时则不相关,因此服务器返回任意内容类型标头没有问题。
letmaik

6

尝试使用xDomain

对于我来说,使用angular或jQuery进行设置非常简单。在您的应用服务器上,按照以下链接中的帮助所述添加proxy.html。在您的“客户端”和中提琴上添加一些引用js文件的标签,无需再进行飞行前检查。它将包装在iframe中,以避免需要进行cors检查。

https://github.com/jpillora/xdomain


1

一种方法是,您可以将所有API调用指向与前端相同的域。在前端服务器上设置nginx,以仅将API调用转发到API服务器。这将删除所有飞行前呼叫。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.