更多详情见http://blog.zhangbing.club/Ja...
最近在项目开发的过程中遇到一些Javascript 跨域请求的问题,今天抽空对其进行总结一下,以备后用,也希望同学们在遇到类似问题的时候可以有所帮助。
Javascript跨域问题是web开发人员最常碰到的一个问题之一。所谓Javascript跨域问题,是指在一个域下的页面中通过js访问另一个不同域下的数据对象,出于安全性考虑,几乎所有浏览器都不允许这种跨域访问,这就导致在一些ajax和iframe应用中,使用跨域的web service会成为一个问题。
那到底什么是跨域,简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。更详细的说明可以看下表:
特别注意两点:
“URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”(本段来自网络,个人觉得这段对js跨域描述得在清晰不过了)。跨域请求无处不在,平时我们在开发活动过程中,活动静态页面通过Javascript访问前端CGI就是明显的主域相同,子域不同的跨域例子,一般活动静态页面都是类似这样的(http://业务名.xx.com/act/活动...,前端CGI 是这样的(http://www.xx.com/act/活动目... 下面来看看我们都是如何处理跨域请求的:
虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,script标签的src属性引用指向接收方的一个处理地址(后台),该地址返回的javascript方法会被执行,另外URL中可以传入一些参数,该方法只支持GET方式提交参数。我们常用FloadJS方法用的就是这种跨域方式。
Jquery 的getScript 和 getJson方法都可以调用跨域的js或服务端脚本,但是它们的实现原理不一样。
1.getScript 方法 语法:jQuery.getScript(url,success(response,status)) 该函数是简写的 Ajax 函数,等价于:
$.ajax({
Type: get,
url: url,
dataType: "script",
success: success
});
jQuery 1.2 版本之前,getScript 只能调用同域 JS 文件。 1.2中,您可以跨域调用 JavaScript 文件。注意:Safari 2 或更早的版本不能在全局作用域中同步执行脚本。如果通过 getScript 加入脚本,请加入延时函数。
实现跨域的原理:通过 GET 方式请求载入并执行一个 JavaScript 文件, 相当于通过src的形式的导入一个外部的js
2.getJson方法 语法:jQuery.getJSON(url,data,success(data,status,xhr)) 该函数是简写的 Ajax 函数,等价于:
$.ajax({
url: url,
data: data,
success: callback,
dataType: json
});
在jQuery 1.2 中,您可以通过使用 JSONP 形式的回调函数来加载其他网域的 JSON 数据,如 "myurl?callback=?"。jQuery 将自动替换 ? 为正确的函数名,以执行回调函数。
实现跨域的原理:采用Jsonp原理实现跨域
到这里大家有没有发现一个问题,好像一直都在讨论http get 请求方式的跨域问题,难道post 请求就不存在跨域问题吗?其实原生态From 表单 POST 到一个后台处理脚本是不存在跨域问题,因为提交过程不牵涉到JS操作其它域名的对象,可是POST表单后,页面会刷新,给用户带来的体验不佳,这时我们经常会想到用jquery ajax post 方法来提交表单, 虽然这种方式不会刷新页面,但是会存在跨域问题。因为ajax本身实际上是通过XMLHttpRequest对象来进行数据的交互,而浏览器出于安全考虑,是不允许js代码进行跨域操作,进而会发警告,所以jquery ajax post 是行不通的,可能这时有人会说,用jsonp数据类型啊,但是jsonp目前只支持get请求方式,对post请求不支持。我们在平时开发过程又不得不用post方式,因为get方式对请求的数量有大小限制,那在这种情况下如何保证用户良好的页面体验,又能解决跨域问题呢? 其实这时我们可以用最常见的document.domain + iframe 方式来实现。
这种方式只适用主域名相同,子域名不同的情形,在我们项目开发过程,这种方式还是比较适用。
从上面的说明可以看到,客户端的解决方案局存在一定的局限性,而且对于ajax跨域请求,无论两个域是否属于同个基础域,都无法在客户端加以解决,也就是说如果我们要想在ajax请求中访问其他域下的数据,就只能通过服务端进行处理了。服务端的解决方案的基本原理就是,由客户端将请求发给本域服务器,再由本域服务器的代理来请求数据并将响应返回给客户端。
HTML5中最酷的新功能之一就是 跨文档消息传输Cross Document Messaging。下一代浏览器都将支持这个功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。 otherWindow.postMessage(message, targetOrigin); otherWindow: 对接收信息页面的window的引用。可以是页面中iframe的contentWindow属性;window.open的返回值;通过name或下标从window.frames取到的值。 message: 所要发送的数据,string类型。 targetOrigin: 用于限制otherWindow,“*”表示不作限制 a.com/index.html中的代码。 但是HTML5 在IE6, IE7浏览器下不兼容,目前移动端解决跨域问题用得比较多, PC机上用得比较少。
如果你要读取一个外部文件,比如swf,picture,mp3等等,那么就需要一个跨域策略文件,allow-access-from domain表示允许访问的URl,如果有多个依次添加,如果允许所有就一个 allow-access-from domain = "*"就可以了。
在项目开发过程如果能用get方式解决的就尽量使用它,毕竟get的性能也比post高,而且处理get跨域请求的方法也比较多,比如用jquery库的 getScript和getJson方法。如果提交的数据比较大,一定用post方式提交,并且考虑用户的功能体验,可以用document.domain + iframe的方式来处理。