JS实现跨域的几种方式

JS通过ajax去请求非同源中的资源时会出现跨域请求。

同源定义

如果两个页面拥有相同的协议(protocol),端口(如果指定),和主机,那么这两个页面就属于同一个源(origin)。

下表给出了相对http://store.company.com/dir/page.html同源检测的示例:

URL结果原因
http://store.company.com/dir2/other.html成功
http://store.company.com/dir/inner/another.html成功
https://store.company.com/secure.html失败协议不同
http://store.company.com:81/dir/etc.html失败端口不同
http://news.company.com/dir/other.html失败主机名不同

跨域资源共享(CORS)

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

通过CORS实现访问非同源下的资源,主要是通过在服务器端设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。

Access-Control-Allow-Origin:<origin> | *
- * : 表示允许来自所有域的请求,一般不这样做。
- <origin> : 设置具体的域,只能改域可以请求。

JS:
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://gay.huntuns.com/PHP/ajax.php?a=1', true);
xhr.send();
</script>   

PHP:
<?php
header('Access-Control-Allow-Origin: http://127.0.0.1');
$arr = array(
    'name'      => 'ayguo',
    'address'   => '北京'
);
echo json_encode($arr);
?>

images

Access-Control-Allow-Origin设置的源就是Request Headers中的Origin,如图中箭头所指。注:源最后面不需要加/

通过jsonp跨域

JSONP(JSON with Padding)是资料格式 JSON 的一种“使用模式”,可以让网页从别的网域要资料。
JSONP也叫填充式JSON,是应用JSON的一种新方法,只不过是被包含在函数调用中的JSON,例如:

callback({name: "ayguo", address: "北京"})

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

JS:
<script>
var script = document.createElement('script');
script.src = 'http://gay.huntuns.com/PHP/ajax.php?jsonp=callback';
document.getElementsByTagName('head')[0].appendChild(script);


function callback(res){
    console.log(res); //Object {name: "ayguo", address: "北京"}
}
</script>

PHP:

<?php
$arr = array(
    'name'      => 'ayguo',
    'address'   => '北京'
);
echo $_GET['jsonp'].'('.json_encode($arr).')';
?>

添加的script会返回一个回调函数,如下:
image

CORS和JSONP对比

CORS与JSONP相比,无疑更为先进、方便和可靠。

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

window.name+iframe实现跨域

window.name (一般在js代码里出现)的值不是一个普通的全局变量,而是当前窗口的名字,这里要注意的是每个iframe都有包裹它的window,而这个window是top window的子窗口,而它自然也有window.name的属性,window.name属性的神奇之处在于name值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)。

其实现原理:就是利用window.name在页面地址发生变化后,其值不变。我们在页面上建一个iframe标签,将其src指向服务器请求的地址(将数据放在windwo.name上),当加载完毕后再把iframe里面的地址指向当前页面的地址(同源即可)。

JS:

// window.name+iframe实现跨域
function crossDomain(url, callback){

    var flag = true;
    var ifr = document.createElement('iframe');
    ifr.style.display = "none";

    var fn = function(){
        // flag 防止重复加载
        if(flag){
            flag = false;
            ifr.contentWindow.location = 'http://127.0.0.1/';
        }else{
            callback(ifr.contentWindow.name);

            // 销毁iframe
            ifr.contentWindow.document.write('');
            ifr.contentWindow.close();
            document.body.removeChild(ifr);
            ifr.src = '';
            ifr = null;

        }
    }

    // iframe.onload在IE下有问题
    if(window.attachEvent){
        ifr.attachEvent('onload', fn);
    }else{
        ifr.onload = fn;
    }

    // 指定src
    ifr.src = url;
    document.body.appendChild(ifr);

}


// 测试
crossDomain('http://gay.huntuns.com/PHP/ajax.php', function(res){
    console.log(res);
});


PHP:

echo '<script>window.name="{name: \'ayguo\', age: 23}";</script>';

结果:
image

参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值