前端遇到的跨域问题及解决方案一
《JavaScript 高级程序设计》一直断断续续的看这本书,有些地方看了三四遍,有些地方一遍也没有看过。这本书真心是非常不错的书,再随着google些资料,还是受益很多的。
昨睡不着,翻了下看看跨域,今又认真搜了下,有跟先前不一样的体会了。工作中遇到的跨域,比如说iframe引用某某盛典的页面,你是没有办法设置高度的~~有嵌套iframe的方法获取高度,但是对方这个页面不是你一家用的,你不能有任何修改,它是不会内嵌什么iframe的。真心没办法解决~~ 有些东西,你是甲方的话,别家提供,基本是采用JSONP方式,约定个函数传递数据,或者是直接链别家的JS文件有全局对象。
让我们从书开始吧~
Ajax跨域请求问题
Ajax是无需刷新页面就能够从服务器去的数据的一种方法。负责Ajax运作的核心对象是XMLHttpRequest(XHR)对象。同源策略是对XHR的一个主要约束,它为通信设置了“相同的域、相同的端口、相同的协议”这一限制。试图访问上述限制之外的资源都会引发安全错误,除非采用被认可的跨域解决方案。这个方案叫做CORS(Cross-Origin Resource Sharing ,跨源资源共享。)提一句,对于未被授权系统有权访问某个资源的情况,称之为CSRF(Cross-Site Request Forgery, 跨站点请求伪造)。
CORS
CORS背后的基本思想,是用用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。
比如一个简单的使用GET或POST发送的请求,它没有自定义的头部,而主体内容是text/plain。在发送该请求时,需要给它附加一个额外的Origin头部,其中包含请求页面的源信息(协议、域名、端口),以便服务器根据这个头部信息来决定是否给予响应。示例
Origin: http://www.cnblogs.com/
如果服务器认为这个请求可以接受,就在Access-Control-Allow-Origin头部中回发相同的源信息(如果过是公共资源,可以回发”*”)。
Access-Control-Allow-Origin:http://www.cnblogs.com/
如果没有这个头部,或这个有这个头部但源信息不匹配,浏览器就会驳回请求。正常情况下,浏览器会处理请求。注意,请求和响应中都不包含cookie信息。
IE对CORS的实现
IE8引入了XDR(XDomainRequest)类型。与XHR类似,但能实现安全可靠的跨域通信。所有XDR请求都是异步的,不能用它来创建同步请求。请求返回之后,会触发load事件,响应数据也会保存在responseText属性中。
var xdr=new XDomainRequest(); xhr.onload=function(){ console.log(xhr.responseText); } xhr.onerror=function(){ console.log("Error"); } xdr.timeout=1000; xdr.ontimeout=function(){ console.log("Request took too long"); }; xdr.open("get","http://www.cnblogs.com/yixiaoheng/"); xdr.send(null);
其他浏览器对CORS的实现
Firefox3.5+、Safari4+、Chrome、iOS版Safari和Android平台中的WebKit都通过XMLHttpRequest对象实现对CORS的原生支持。在尝试打开不同来源的资源时,无需额外编写代码就可以触发这个行为。要请求位于另一个域中的资源,使用标准的XHR对象并在open()方法中传入绝对URL即可。
var xhr=createXHR(); xhr.onreadystatechange=function(){ if(xhr.readyState==4){ console.log(xhr.responseText); }else{ console.log("Request was fail "+xhr.status); } }; xhr.open("get","http://www.cnblogs.com/yixiaoheng/",true); xhr.send(null)
JSONP
JSONP是JSON with padding(填充式JSON或参数式JSON)的简写,它是被包含在函数调用中的JSON 像这样callback({“name”:”Fany”})。
JSONP由两部分组成:回调函数和数据。会掉函数是响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的JSON数据。下面是一个典型的JSONP请求。
http://freegeoip.net/json/?callback=handleResponse
你可以使用$.getJSON()来处理返回数据。
JSONP在开发人员中极为流行,主要原因是它非常简单易用。与图像Ping相比,它的优点在于能够直接访问响应文本,支持在浏览器和服务器之间的双向通信。
缺点
首先,JSONP是从其他域中加载代码执行。如果其他域不安全,很可能会在响应中夹带一些恶意的代码,而此时除了完全放弃JSONP调用之外,没有办法追究。
其次,要确定JSONP请求是否失败并不容易。开发人员不得不使用计时器检测指定时间内是否接收了响应。
服务器代理请求
这个方案中心思想是在页面发送请求给本域服务器的一个代理脚本,代理脚本来完成对它域的请求,然后把结果返回给客户端。它的优点是可以完全模拟请求方法(无论GET还是POST),并把参数和客户端Cookies传递过去。
这个方案能完成Jsonp不能完成的Post请求,但是实施起来比Jsonp麻烦的多。这里有一个PHP的实现方案可以参考,你可以先看下Yahoo团队的解决方案 JavaScript: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls 因为方案是PHP我仅是了解重点,你需要Proxy!
上面的三个方案主要解决Ajax跨域请求问题。
还有个不一样的跨域方式是图像Ping
图像Ping
可以从任何网页中加载图像,不用担心跨域。这也是在线广告跟踪浏览量的主要方式,如跟踪用户点击页面或动态广告曝光次数。
动态创建图像经常用于图像Ping.图像Ping是与服务器进行简单、单项的跨域通信的一种方式。请求的数据是通过查询字符串形式发送的,而相应可以是任意内容,但通常是像素图或204相应。通过图像Ping,浏览器得不到任何具体的数据,但通过侦听load和error,能知道响应式什么死后接收到的。例子:
var img=new Image(); img.onload=img.onerror=function(){ console.log("Done"); } img.src="http://example.com/test?name=fany";
缺点
一是只能发送get请求,二是无法访问服务器的相应文本。图像Ping只能用于浏览器与服务器间的单向通信。
还有Flash跨域的解决方法,有几年不看这个了,所以没有仔细核实。罗列分享下吧
Flash URLLoader
Flash有自己的一套安全策略,服务器可以通过crossdomain.xml文件来声明能被哪些域的SWF文件访问,SWF也可以通过API来确定自身能被哪些域的SWF加载。当跨域访问资源时,例如从域www.a.com请求域www.b.com上的数据,我们可以借助Flash来发送HTTP请求。首先,修改域www.b.com上的crossdomain.xml(一般存放在根目录,如果没有需要手动创建) ,把www.a.com加入到白名单。其次,通过Flash URLLoader发送HTTP请求,最后,通过Flash API把响应结果传递给JavaScript。Flash URLLoader是一种很普遍的跨域解决方案,不过需要支持iOS的话,这个方案就无能为力了。
Flash LocalConnection
页面上的双向通信也可以通过Flash来解决,Flash API中有LocalConnection这个类,该类允许两个SWF之间通过进程通信,这时SWF可以播放在独立的Flash Player或者AIR中,也可以嵌在HTML页面或者是PDF中。遵循这个通信原则,我们可以在不同域的HTML页面各自嵌套一个SWF来达到相互传递数据的目的了。SWF通过LocalConnection交换数据是很快的,但是每次的数据量有40kb的大小限制。用这种方式来跨域通信过于复杂,而且需要了2个SWF文件,实用性不强。
解决不同域之间JS交互又有哪些方式呢?