CORS数据获取
本文作者:Todd Anglin最初发表在剑道UI博客于2011年10月3日发布,并于2012年7月更新。
为了保持一致性,这里保留了条目的原始拼写、语法和结构。
在所有(现代)浏览器中使用CORS
跨地域资源共享是一种(缓慢)新兴的web技术,最终提供了一种直接从不同域获取资源的异步web操作方法。事实上,我们已经在剑道UI博客上讨论过CORS几次了在这里而且在这里.
默认情况下,同源所有浏览器内置的安全沙箱不允许跨不同域调用XHR (Ajax)。你可以尝试一下,但是你会得到一个类似这样的错误:
XMLHttpRequest无法加载[URL]。Access-Control-Allow-Origin不允许Origin[您的网站]。
这条消息基本上是说您不能使用Ajax从不同的域加载资源。但最后的误差是什么呢?
Access-Control-Allow-Origin
CORS的工作原理是在从服务器到客户端的响应中添加一个特殊的报头。如果响应包含Access-Control-Allow-Origin
如果浏览器支持CORS,那么就有机会直接使用Ajax&dmash加载资源;不需要代理或JSONP黑客.
为什么只是一个机会?
标头能够指定允许哪些远程站点加载跨源资源。例如,在一个假设的响应中考虑以下CORS头:Access-Control-Allow-Origin [http://htmlui.com] (http://htmlui.com/)
.
使用此配置,只有起源于http://htmlui.com允许从哪里加载资源telerik.com
.试图使用Ajax从其中加载资源的任何其他域telerik.com
将给出标准的安全错误消息。通过这种方式,站点所有者可以限制允许哪些域使用CORS加载其资源。
或者,网站所有者可以授予完全开放的访问权限,并标注“随时准备参加聚会”星号:__Access-Control-Allow-Origin: * __
.
现在,任何想要直接使用Ajax加载资源的站点都可以这样做,而不会出现浏览器安全错误。这项技术对于经常使用JavaScript加载数据的现代应用程序很有帮助,而且越来越多的现代web api正在考虑支持CORS。要查看CORS的运行情况,请参见GeoNames.org,last . fm,谷歌api。
服务器端设置
显然,CORS是强大的。它打开了严格控制的浏览器安全沙箱,这对受信任的网络结构至关重要。正如你所期望的那样,这是一个必须由网站所有者做出的决定(你不能在不允许使用CORS的网站上使用它),它由web服务器配置控制。
任何人都可以通过简单地让web服务器添加必要的cors来启用他们的站点Access-Control-Allow-Origin
头。事实上,有一个完整的网站致力于向你展示如何为不同的web服务器主机添加此标头。在Apache中,只需将这一行添加到htaccess文件
:头设置Access-Control-Allow-Origin *
处理浏览器
使用浏览器从来都不简单,特别是当您希望确保广泛的兼容性时。
经证实是有用的CanIUse.com
在美国,对CORS的支持是一个大杂烩。CORS已经100%准备就绪:
- WebKit浏览器(Chrome, Safari, iOS, Android)
- 壁虎浏览器(Firefox)
- Trident浏览器(Internet Explorer 8+)
- 快速浏览器(特别是Opera 12+)
还不错。直到最近,Opera才从这个名单中消失,但随着2012年年中Opera 12的发布,Opera现在也支持CORS.
我们将在一分钟内讨论如何处理旧的Opera版本,但让我们首先讨论IE。
Internet Explorer和XDomainRequest
IE10之前的ie浏览器在跨源资源共享方面稍有不同。ie8和ie9没有走WebKit和Gecko的路线,而是没有重用标准AjaxXMLHttpRequest
对象用于CORS请求。相反,它们为跨起源资源共享引入了一个全新的对象XDomainRequest
.
这意味着跨域调用的Ajax代码看起来100%相同同一域
在Chrome和Firefox中调用,但它将不得不在Internet Explorer中使用新的XDR对象和CORS请求。痛苦,但却是可以解决的问题。XDR还有其他一些限制,但是我们把这个留给你们去研究.
通过这个小片段,我们可以编写适用于CORS XHR, XDR的代码,当它不起作用时,可以使用某种后备方法:
//检测浏览器对CORS的支持if ('withCredentials' in new XMLHttpRequest()){/*支持跨域请求*/ document. xmlwrite("支持CORS (XHR)");} else{if(typeof XDomainRequest !== "undefined"){//在XDR文档中使用特定于ie的"CORS"代码。write("支持CORS (XDR)");}else{//使用回退或填充文档撤退的时间。写(“没有CORS支持!”);}}
你可以在不同的浏览器中尝试此代码片段来证实它有效。
的XMLHttpRequest2
对象,其中包括所需的CORS支持,可用于CORS的功能检测浏览器支持。如果浏览器XHR
对象具有XHR2“withCredentials”
财产,你在做生意。如果没有,请执行步骤2。
在第2步中,我们再次尝试使用CORS,查找IE的专有版本XDomainRequest
对象(使用相同的Access-Control-Allow-Origin
顺便说一下,是头文件)。如果XDR对象存在,我们就在IE中,可以编写必要的代码来执行XDR CORS。
最后,如果所有这些都失败了(例如在旧版本的Opera或IE6/7中),我们必须提供另一种体验或为CORS找到一个hack。
处理Opera(或非cors浏览器)
假设我们达到了XHR2 /歌珥
而且XDR
都没有,下一步怎么办?放弃歌珥吗?事实证明,你有几个选择。您可以:
使用CORS填充材料有几个比较“俗气”的用于CORS的填料依赖于A)隐藏的Flash,或B)一些巫术HTML5。无论哪种方式,它们都绕过了浏览器限制,并试图为您提供一些表面上的CORS支持。
当然,如果您可以使用JSONP,那么对于所有浏览器,您都可以使用JSONP而不是CORS,因为它仍然受到更广泛的支持。但是,假设您试图“进化”过去的JSONP,除非您绝对需要它。在这种情况下,您可以使用Opera和旧浏览器退回到XHR和JSONP回调。
显示一个错误信息这是您最严厉的选择,但已给出大多数浏览器做支持CORS,您可以简单地选择告诉一小部分用户更新他们的浏览器。这取决于Opera和IE 6/7流量对你的网站有多重要。
选择权在你,但显然,你有选择权一些这样的选择仍然会使CORS具有吸引力。
把它们放在一起
在剑道UI提要阅读器演示,我们使用YQL将RSS XML直接提供给浏览器。YQL支持CORS,因此我们选择将XML而不是JSONP发送到浏览器来突出显示Kendo UI对XML的数据源支持.
这个演示的版本1不支持非cors浏览器。为了增加对这些浏览器的支持,我们修改了代码,在IE中使用XDR,在Opera和所有非cors浏览器中使用YQL JSONP。
修复IE的jQuery $。ajax传输
使CORS代码与IE 8/9一起工作实际上非常容易一些代码写的德里克Kastner.使用jQuery 1.5+,您可以创建自定义传输实现来控制jQuery $.ajax的内部工作。德里克用XDR就做到了这一点。
他的iecors
项目简单地在jQuery $中创建一个使用XDR的jQuery传输。Ajax在需要时请求。你所要做的就是把这个小的JS文件添加到你的页面,然后一切就开始工作了(不改变你的代码)。Kendo UI数据源,使用jQuery $。ajax在封面下,现在将在IE中使用XDR。
所以,为了让Feed Reader演示CORS在IE 8/9中工作,一个小片段被添加到页面底部,在jQuery之后,但在任何剑道脚本引用之前:
<!——[if lt IE 10]> < script src="scripts/ jQuery .iecors.js">
用更多代码和JSONP修复Opera
不幸的是,修复旧版本的Opera并不那么容易。最终,在Opera中没有干净的方法来做CORS。您可以选择为Opera (v12之前)用户显示“浏览器不支持”的消息,或者在CORS无法工作时咬紧牙关“退回”到YQL JSONP。
我们选择在Feed Reader演示中使用后一种方法,因为它还有助于扩展对其他旧浏览器的支持。
//**HACK for OPERA(和非xhr2 /XDR浏览器)//由于缺乏合理的OPERA工作方法来支持CORS,退一步使用//YQL支持JSONP时处理浏览器比不支持//CORS XHR或XDR如果(!('withCredentials' in new XMLHttpRequest()) && !(typeof XDomainRequest !== "undefined")){_feedItemDS = new kendo.data。DataSource({传输:{读取:{url: "#",数据类型:"jsonp"},方言:函数(选项){var result = ["callback=?","format=json"], data = options || {};返回result.join(“&”);}}, schema:{type:"json", data:"query.results.rss.channel. "Item ",}});//**END OPERA/非cors HACK}
现在,Opera(任何其他非cors浏览器)将使用指向JSONP端点的Kendo UI数据源的备用配置,并期待JSON响应。不是漂亮的代码,但它是功能性的。有时,这就是构建在每个主要浏览器和平台上运行的软件所需要的。
关于CORS的底线
希望这篇文章有助于强调CORS的价值,以及它如何与大多数现代浏览器一起使用。随着越来越多的应用程序代码转移到客户端,对CORS的需求只会增长。从今天开始使用它,帮助将web标准推向下一个水平。