javascript跨域

更多详情见http://blog.zhangbing.club/Ja...

最近在项目开发的过程中遇到一些Javascript 跨域请求的问题,今天抽空对其进行总结一下,以备后用,也希望同学们在遇到类似问题的时候可以有所帮助。

Javascript跨域问题是web开发人员最常碰到的一个问题之一。所谓Javascript跨域问题,是指在一个域下的页面中通过js访问另一个不同域下的数据对象,出于安全性考虑,几乎所有浏览器都不允许这种跨域访问,这就导致在一些ajax和iframe应用中,使用跨域的web service会成为一个问题。

javascript跨域图表

那到底什么是跨域,简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。更详细的说明可以看下表:

特别注意两点:

  • 第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,
  • 第二:在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。

“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/活动目... 下面来看看我们都是如何处理跨域请求的:

动态创建script

虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,script标签的src属性引用指向接收方的一个处理地址(后台),该地址返回的javascript方法会被执行,另外URL中可以传入一些参数,该方法只支持GET方式提交参数。我们常用FloadJS方法用的就是这种跨域方式。

使用Jquery中getScript和getJson方法实现跨域

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 方式来实现。

document.domain + iframe

这种方式只适用主域名相同,子域名不同的情形,在我们项目开发过程,这种方式还是比较适用。

服务端代理

从上面的说明可以看到,客户端的解决方案局存在一定的局限性,而且对于ajax跨域请求,无论两个域是否属于同个基础域,都无法在客户端加以解决,也就是说如果我们要想在ajax请求中访问其他域下的数据,就只能通过服务端进行处理了。服务端的解决方案的基本原理就是,由客户端将请求发给本域服务器,再由本域服务器的代理来请求数据并将响应返回给客户端。

使用HTML 5 postMessage方式

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机上用得比较少。

使用flash

如果你要读取一个外部文件,比如swf,picture,mp3等等,那么就需要一个跨域策略文件,allow-access-from domain表示允许访问的URl,如果有多个依次添加,如果允许所有就一个 allow-access-from domain = "*"就可以了。

个人小结

在项目开发过程如果能用get方式解决的就尽量使用它,毕竟get的性能也比post高,而且处理get跨域请求的方法也比较多,比如用jquery库的 getScript和getJson方法。如果提交的数据比较大,一定用post方式提交,并且考虑用户的功能体验,可以用document.domain + iframe的方式来处理。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券