JS跨域

跨域概述

两个差异域相互要求,称为跨域,是由浏览器同源战略限定的一类要求场景。

–> 同源战略/SOP(Same origin policy)是浏览器最中心也最基础的平安功用,假如缺少了同源战略,浏览器很轻易遭到CSFR等进击。所谓同源是指”协定+域名+端口”三者雷同。

同源战略限定以下几种行动:
1.) Cookie、LocalStorage 和 IndexDB 没法读取<br/>
2.) DOM没法取得<br/>
3.) AJAX 要求不能发送

现在主流的用于处置惩罚跨域题目的要领:

iframe跨域

document.domain+iframe

瑕玷:这类要领只实用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 没法经由历程这类要领。

完成道理:两个页面都经由历程js强迫设置document.domain为基础主域,就完成了同域。

1.)父窗口:(http://www.domain.com/a.html)

<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
    document.domain = 'domain.com';
    var user = 'admin';
</script>

2.)子窗口:(http://child.domain.com/b.html)

<script>
    document.domain = 'domain.com';
    // 猎取父窗口中变量
    alert('get js data from parent ---> ' + window.parent.user);
</script>

–>iframe是什么?iframe 元素会建立包括别的一个文档的内联框架(即行内框架)

postMessage跨域

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多能够跨域操纵的window属性之一,它可用于处置惩罚以下方面的题目:<br/>
a.) 页面和其翻开的新窗口的数据通报<br/>
b.) 多窗口之间音讯通报<br/>
c.) 页面与嵌套的iframe音讯通报<br/>
d.) 上面三个场景的跨域数据通报

用法:postMessage(data,origin)要领吸收两个参数

  • data: html5范例支撑恣意基础范例或可复制的对象,但部份浏览器只支撑字符串,所以传参时最好用JSON.stringify()序列化。
  • origin: 协定+主机+端口号,也能够设置为*,示意能够通报给恣意窗口,假如要指定和当前窗口同源的话设置为”/”。

1.)a.html:(http://www.domain1.com/a.html)

<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>       
    var iframe = document.getElementById('iframe');
    iframe.onload = function() {
        var data = {
            name: 'aym'
        };
        // 向domain2传送跨域数据
        iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
    };

    // 吸收domain2返回数据
    window.addEventListener('message', function(e) {
        alert('data from domain2 ---> ' + e.data);
    }, false);
</script>

2.)b.html:(http://www.domain2.com/b.html)

<script>
    // 吸收domain1的数据
    window.addEventListener('message', function(e) {
        alert('data from domain1 ---> ' + e.data);

        var data = JSON.parse(e.data);
        if (data) {
            data.number = 16;

            // 处置惩罚后再发还domain1
            window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
        }
    }, false);
</script>

window.name+iframe

window.name属性的奇特的地方:name值在差异的页面(以至差异域名)加载后照旧存在,而且能够支撑异常长的 name 值(2MB)。

1.)a.html:(http://www.domain1.com/a.html)

var proxy = function(url, callback) {
    var state = 0;
    var iframe = document.createElement('iframe');

    // 加载跨域页面
    iframe.src = url;

    // onload事宜会触发2次,第1次加载跨域页,并保存数据于window.name
    iframe.onload = function() {
        if (state === 1) {
            // 第2次onload(同域proxy页)胜利后,读取同域window.name中数据
            callback(iframe.contentWindow.name);
            destoryFrame();

        } else if (state === 0) {
            // 第1次onload(跨域页)胜利后,切换到同域代办页面
            iframe.contentWindow.location = 'http://www.domain1.com/proxy.html';
            state = 1;
        }
    };

    document.body.appendChild(iframe);

    // 猎取数据今后烧毁这个iframe,开释内存;这也保证了平安(不被其他域frame js接见)
    function destoryFrame() {
        iframe.contentWindow.document.write('');
        iframe.contentWindow.close();
        document.body.removeChild(iframe);
    }
};

// 要求跨域b页面数据
proxy('http://www.domain2.com/b.html', function(data){
    alert(data);
});

2.)proxy.html:(http://www.domain1.com/proxy….
中心代办页,与a.html同域,内容为空即可。

3.)b.html:(http://www.domain2.com/b.html)

<script>
    window.name = 'This is domain2 data!';
</script>

总结:经由历程iframe的src属性由外域转向当地区,跨域数据即由iframe的window.name从外域通报到当地区。这个就奇妙地绕过了浏览器的跨域接见限定,但同时它又是平安操纵。

AJAX跨域

Vue ProxyTable

实质是建立当地服务器,由当地服务器要求跨域服务器上的数据,服务器之间没有同源限定,

Access-Control-Allow-Origin参数设置

在被要求的文件中增添一个header(IE10以下不支撑)

<?php
header("Access-Control-Allow-Origin:*");
?>

jsonp要领

瑕玷:只能完成get一种要求。
长处:简朴实用,老式浏览器悉数支撑,服务器革新异常小。

道理:网页经由历程增添一个<script>元素,向服务器要求JSON数据,这类做法不受同源政策限定;服务器收到要求后,将数据放在一个指定名字的回调函数里传返来。

原生完成

//js
function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};

//服务端
<?php 
$callback = $_GET['foo']//获得回调函数名
$data = array('a','b','c');  //要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>

JQuery要领

jquery会自动天生一个全局函数来替代callback=?中的问号,以后猎取到数据后又会自动烧毁,实际上就是起一个暂时代办函数的作用。

get

$.get('http://example.com/data.php?callback',function(){
        alert('123');
},'jsonp');

<?php 
$callback = $_GET['callback']//获得回调函数名
$data = array('a','b','c');  //要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>

getJson

getJSON要领会自动推断是不是跨域,不跨域的话,就挪用一般的ajax要领;跨域的话,则会以异步加载js文件的情势来挪用jsonp的回调函数。

$.getJson('http://example.com/data.php?callback=?',function(){
    alert('123');
});

<?php 
$callback = $_GET['callback']//获得回调函数名
$data = array('a','b','c');  //要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>

ajax包裹jsonp

以上做法另有一种诠释就是JQuery把jsonp的完成封装在了ajax中

$.ajax({ 
    type: "GET",     
    url: "http://www.b.com/jsonp.js"
    dataType: "jsonp",
    jsonp:"callback",//“callback”:恣意名字都能够
    success: function(data) {
        //对data的处置惩罚
    },
    error: function(jqXHR){     
        alert("发作毛病:" + jqXHR.status);  
    },     
});

//服务端的修正
$jsonp = $_GET["callback"];//callback名字和要求的名字雷同

–>ajax是什么?经由历程在背景与服务器举行少许数据交换,AJAX 能够使网页完成异步更新。这意味着能够在不从新加载全部网页的情况下,对网页的某部份举行更新。

vue完成jsonp

//vue js
this.$http.jsonp('http://www.domain2.com:8080/login', {
    params: {},
    jsonp: 'onBack'
}).then((res) => {
    console.log(res); 
})
 
//node.js后端代码
var querystring = require('querystring');
var http = require('http');
var server = http.createServer();

server.on('request', function(req, res) {
    var params = qs.parse(req.url.split('?')[1]);
    var fn = params.callback;

    // jsonp返回设置
    res.writeHead(200, { 'Content-Type': 'text/javascript' });
    res.write(fn + '(' + JSON.stringify(params) + ')');

    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

WebSocket协定跨域

WebSocket是HTML5新的一种通讯协定,运用ws://(非加密)和wss://(加密)作为协定前缀。该协定不实行同源政策,只需服务器支撑,就能够经由历程它举行跨源通讯。

下面是一个例子,浏览器发出的WebSocket要求的头信息。

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

上面代码中,有一个字段是Origin,示意该要求的要求源(origin),即发自哪一个域名。恰是由于有了Origin这个字段,所以WebSocket才没有实行同源政策。由于服务器能够依据这个字段,推断是不是许可本次通讯。假如该域名在白名单内,服务器就会做出以下回应。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

CORS

CORS是跨源资本分享(Cross-Origin Resource Sharing)的缩写。它是W3C规范,是跨源AJAX要求的基础处置惩罚要领。比拟JSONP只能发GET要求,CORS许可任何范例的要求。IE浏览器不能低于IE10。

全部CORS通讯历程,都是浏览器自动完成,不需要用户介入。关于开发者来讲,CORS通讯与同源的AJAX通讯没有差异,代码完整一样。浏览器一旦发明AJAX要求跨源,就会自动增添一些附加的头信息,偶然还会多出一次附加的要求,但用户不会有觉得。

因而,完成CORS通讯的关键是服务器。只需服务器完成了CORS接口,就能够跨源通讯。

简朴要求

只需同时满足以下两大前提,就属于简朴要求。

(1) 要求要领是以下三种要领之一:
HEAD
GET
POST
(2)HTTP的头信息不超越以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

关于简朴要求,浏览器直接发出CORS要求。具体来讲,就是在头信息当中,增添一个Origin字段。

下面是一个例子,浏览器发明此次跨源AJAX要求是简朴要求,就自动在头信息当中,增添一个Origin字段。

GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

假如Origin指定的源,不在许可范围内,服务器会返回一个一般的HTTP回应。假如Origin指定的域名在许可范围内,服务器返回的相应,会多出几个头信息字段。

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

非简朴要求

非简朴要求是那种对服务器有特殊要求的要求,比方要求要领是PUT或DELETE,或许Content-Type字段的范例是application/json。

非简朴要求的CORS要求,会在正式通讯之前,增添一次HTTP查询要求,称为”预检”要求(preflight)。”预检”要求用的要求要领是OPTIONS,示意这个要求是用来讯问的。”预检”要求的HTTP头信息:

Origin: 要求域名
Access-Control-Request-Method: 要求本身的要领
Access-Control-Request-Headers: 自定义的头部信息

发送要求后,服务器能够决议是不是许可这类范例的要求,服务器经由历程在相应中发送以下头部与浏览器举行沟通

Access-Control-Allow-Origin: 雷同的源信息,能够是*
Access-Control-Allow-Methods: 许可的要领
Access-Control-Allow-Headers: 许可的头部
Access-Control-Max-Age:应当讲这个preflight缓存多久

preflight要求完毕后,效果就根据相应中指定的时刻缓存起来,而为此支付的价值只是第一次发送要求的时刻会多发送一次HTTP要求。

带凭证的要求

CORS要求默许不发送Cookie和HTTP认证信息。假如要把Cookie发到服务器,一方面要服务器赞同,指定Access-Control-Allow-Credentials字段。

Access-Control-Allow-Credentials: true

另一方面,开发者必须在AJAX要求中翻开withCredentials属性。

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

前端XMLHttpRequest要求代码

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDR兼容

xhr.withCredentials = true;// 前端设置是不是带cookie

xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
    }
};

xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send();
    原文作者:Gemma
    原文地址: https://segmentfault.com/a/1190000013772432
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞