跨域的理解

备注:

  1. 端口和协议的不同,只能通过后台来解决
  2. localhost和127.0.0.1虽然都指向本机,但也属于跨域

协议子域名主域名端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。

跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。之所以会跨域,是因为受到了同源策略的限制,同源策略要求源相同才能正常进行通信,即协议域名端口号都完全一致。

同源策略限制内容有:CookieLocalStorageIndexedDB 等存储性内容DOM 节点``AJAX 请求不能发送

但是有三个标签是允许跨域加载资源:

  1. <img src=XXX>
  2. <link href=XXX>
  3. <script src=XXX>

处理跨域的方法:

一、Jsonp

代码示例:

后端:

router.get('/hehe', function (req, res, next) {
    var obj = {'0':'a','1':'b','2':'c'};
    res.send('callbackFunction('+JSON.stringify(obj)+')')//需要将对象转为字符串;
});

前端使用jquery的ajax的jsonp:

$.ajax({
        url: 'http://localhost:3000/index/hehe',//跨域请求的地址,也可用相对路径js/data.js
        type: 'get',
        dataType: 'jsonp',//使用jsonp跨域请求
        jsonpCallback:'callbackFunction'
    })
    .done(function(data) {
        console.log(data)// 控制台打印结果{0: "a", 1: "b", 2: "c"}
    })
    .fail(function() {
        console.log("error");
    });
  1. 利用<script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。
    JSONP由两部分组成:回调函数数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。

  2. JSONP和AJAX对比
    JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但AJAX属于同源策略JSONP属于非同源策略(跨域请求)

  3. JSONP优缺点

  • 优点:兼容性好,在很古老的浏览器中也可以用,简单易用,支持浏览器与服务器双向通信。 可用于解决主流浏览器的跨域数据访问的问题
  • 缺点:只支持GET请求,且只支持跨域HTTP请求这种情况(不支持HTTPS)

JSON、JSONP的区别:

1. JSON返回的是一串数据、JSONP返回的是脚本代码(包含一个函数调用)
 2. JSONP 只支持get请求、不支持post请求
 (类似往页面添加一个script标签,通过src属性去触发对指定地址的请求,故只能是Get请求)

二、CORS

  1. CORS原理

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

核心思想:在服务器端通过检查请求头部的origin,从而决定请求应该成功还是失败。

具体的方法是在服务端设置Response Header响应头中的Access-Control-Allow-Origin为对应的域名,实现了CORS(跨域资源共享),这里出于在安全性方面的考虑就是尽量不要用 *

  1. CORS优缺点
  • CORS要求浏览器(>IE10)和服务器的同时支持,是跨域的根本解决方法,由浏览器自动完成。
  • 优点在于功能更加强大支持各种HTTP Method,缺点是兼容性不如JSONP

三、通过document.domain来跨子域

我们只要把http://www.example.com/a.htmlhttp://example.com/b.html这两个页面的document.domain都设成相同的域名就可以了。

但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。

修改document.domain的方法只适用于不同子域的框架间的交互。

四、使用window.name+iframe来进行跨域

a页面的值传给b页面;

给a页面设置window.name的值;

    window.name = 'hello world'

b页面写一个ifram:

<div>
    <iframe src="http://localhost:8080/config/catalog.html"></iframe>
</div>
var ifr = document.querySelector('iframe')
    ifr.onload = function() {
        console.log('跨域获取数据', ifr.contentWindow.name);//b页面就得到了a页面的数据,为:hello world
        ifr.contentWindow.close();
// 每当改变location的时候,就会重新来一次onload,所以我们希望获取到数据之后,就直接close()
    }

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

window.name的值只能是字符串的形式,这个字符串的大小最大只能允许2M左右

五、postMessage

两个页面之间的相互通信;

A页面上有一个ifram标签B页面:

  1. 根据id名获得ifram的contentWindow。
// 使用$('myIFrame').contentWindow来拿到iframe中页面的window对象,
var iframe = document.getElementById('myIFrame').contentWindow;

2.使用postMessage方法传值。message:信息;domain:地址

iframe.postMessage(message, domain);

B页面监听message事件;

window.addEventListener('message', function(event) {//监听message事件发生
    // 可以将监听发送目标的信息来源;
    if (event.origin !== 'http://localhost:8080') return;
        console.log('B我收到了:  ' + event.data, event);
// 也可以返回给A发送消息;格式一样:targetWindow .postMessage(message,targetOrigin,[ transfer ]);
// event.source.postMessage('B收到消息了:', event.origin);
    }, false);

window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源
postMessage(data,origin)方法接受两个参数

  1. data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。

  2. origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

五、webSocket

Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了

六、代理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章