JavaScript跨域问题

跨域产生的原因

JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象,其实就是因为JavaScript同源策略的限制,只有同一域名下,或者同一域名的不同文件夹之间允许通信.
当两个域具有相同的协议, 相同的端口,相同的host,就可以认为它们是相同的域

同源策略

同源策略是一个很重要的安全理念,它在保证数据的安全性方面有着重要的意义。同源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和操作另外一个域的绝大部分属性和方法
同源策略虽然安全但却影响了跨域资源共享,所以在跨域请求上就产生了很多宝贵经验.

跨域资源共享(CORS)

定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request

服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问

目前的跨域方法

跨域资源共享分为单向跨域和双向跨域

一、通过JSONP(JSON with Padding)跨域

在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不允许的。但是,在页面上引入不同域上的js脚本文件却是可以的,我们可以通过script标记来动态加载其他域的资源,JSONP就是利用这个特性来实现的.

JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据

优点:

  • JSONP属于单向跨域
  • 简单高效,易于实现
  • 兼容性好,大部分浏览器都可运行

缺点:

  • 执行第三方的脚本存在安全隐患,适合受信任的双方使用
  • 支持GET请求而不支持POST等其它类型的HTTP请求
  • 只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题

CORS和JSONP对比

  1. JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求
  2. 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理
  3. JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS

二、使用window.name来进行跨域

window对象有个name属性,该属性在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,不会因新页面的载入而进行重置

我们可以在页面A中用iframe加载其他域的页面B,而页面B中用JavaScript把需要传递的数据赋值给window.name,iframe加载完成之后,页面A修改iframe的地址,将其变成同域的一个地址,然后就可以读出window.name的值了.

优点:
这个方式非常适合单向的数据请求,而且协议简单、安全,不会像JSONP那样不限制地执行

三、通过修改document.domain来跨子域

通过修改document的domain属性,我们可以在域和子域或者不同的子域之间通信。同域策略认为域和子域隶属于不同的域,比如www.a.comsub.a.com是不同的域,这时,我们无法在www.a.com下的页面中调用sub.a.com中定义的JavaScript方法。但是当我们把它们document的domain属性都修改为a.com,浏览器就会认为它们处于同一个域下,那么我们就可以互相调用对方的method来通信了

不过如果你想在http://www.example.com/a.html页面中通过ajax直接请求http://example.com/b.html页面,即使你设置了相同的document.domain也还是不行的,所以修改document.domain的方法只适用于不同子域的框架间的交互.
(修改document.domain属于双向跨域)

四、使用HTML5中新引进的window.postMessage方法来跨域传送数据

window.postMessage(message,targetOrigin)方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome,Opera等浏览器都已经支持该方法

调用postMessage方法的window对象是指要接收消息的那一个window对象

  • 该方法的第一个参数message为要发送的消息,类型只能为字符串;

  • 第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符 *

需要接收消息的window对象,可以通过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。上面所说的向其他window对象发送消息,其实就是指一个页面有几个框架的情况,因为每一个框架都有一个window对象。不同域的框架间是可以获取到对方的window对象的,也可以使用window.postMessage这个方法。

(window.postMessage属于双向跨域)


此外的跨域方式还有

  • flash (单向,双向)
    借助flash发送http请求
    Flash LocalConnection(双向)
  • server proxy(单向)等

猜你喜欢

转载自blog.csdn.net/weixin_34124577/article/details/86918448