前端遇到的跨域问题及解决方案一

《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交互又有哪些方式呢?

posted @ 2014-02-02 22:58  易小亨  阅读(2852)  评论(0编辑  收藏  举报