跨域问题

什么是跨域?
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。

所谓同源是指,域名,协议,端口均相同,例如:

http://www.123.com/index.html 调用 http://www.123.com/server.PHP (非跨域)

http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)

http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)

http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)

http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)

请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。

浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。

解决办法:

JSONP:

动态的创建一个<script>标签,同时src到不同源的服务端url,服务端按照约定返回一段可执行js的代码。类似这样:
callbackFunction([“customername1","customername2"])
而在客户端我们只需要定义一个预定好的回调函数即可。
var callbackFunction = function(data){
    // 处理跨域请求得到的数据
};
var script = $('<script>', {src: 'http://b.a.com/bar'})
$('body').append(script)
//其中的callbackFuncton是我们在客户端定义好的在数据请求成功后要执行的回调函数。

好了总结一下用jsonp请求数据的基本流程。

1. 首先在客户端注册一个callback, 然后把callback的名字传给服务器。
2. 服务器先生成 json 数据。
3. 然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp.
4. 将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
5. 客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里.(动态执行回调函数)

jsonp的缺点

只支持GET请求和JSON格式的数据,传输的数据有限制。
没有关于 JSONP 调用的错误处理。如果动态脚本插入有效,就执行调用;如果无效,就静默失败。失败是没有任何提示的。例如,不能从服务器捕捉到 404 错误,也不能取消或重新开始请求.
JSONP 的另一个主要缺陷是被不信任的服务使用时会很危险。因为 JSONP 服务返回打包在函数调用中的 JSON 响应,而函数调用是由浏览器执行的,这使宿主 Web 应用程序更容易受到各类攻击。

代理:

例如www.123.com/index.html需要调用www.456.com/server.php,可以写一个接口www.123.com/server.php,由这个接口在后端去调用www.456.com/server.php并拿到返回值,然后再返回给index.html,这就是一个代理的模式。相当于绕过了浏览器端,自然就不存在跨域问题。

跨域资源共享(CORS),服务器端(如PHP端)修改header(XHR2方式)
与JSONP不同,CORS 除了GET要求方法以外也支援其他的HTTP要求
header(‘Access-Control-Allow-Origin:‘),这句代码中,服务器允许任何人访问,当然可以设置规定访问的域名,如只允许访问http: //localhost:8080/crcp这个域名下的资源,则把 代替成这个域名即可

//在php接口脚本中加入以下两句即可:
header('Access-Control-Allow-Origin:*');//允许所有来源访问
header('Access-Control-Allow-Method:POST,GET');//允许访问的方式

通过修改document.domain来跨子域
将子域和主域的document.domain设为同一个主域.前提条件:这两个域名必须属于同一个基础域名,而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域

window.name实现跨域
name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)
原理:当在浏览器中打开一个页面,或者在页面一个中添加一个iframe时即会创建一个对应的window对象,当页面加载另一个新的页面时,window的name属性是不会变的,这样就可以利用在页面动态添加一个iframe然后src加载数据页面,在数据页面将需要的数据赋值给window.name,然而此时承载iframe的parent页面还是不能直接访问,不在同一域下iframe的name属性,这时只需要将iframe再加载一个与承载页面同域的空白页面,即可对window.name进行数据读取
www.test.com下a.html页:

<script type="text/javascript">

        var a=document.getElementsByTagName("button")[0];

        a.onclick=function(){                               //button添加click事件
            var inf=document.createElement("iframe");       //创建iframe
            inf.src="http://www.domain.com/window.name/b.html"+"?h=5"  //加载数据页www.domain.com/window.name/b.html同事携带参数h=5
            var body=document.getElementsByTagName("body")[0];
            body.appendChild(inf);                          //引入a页面

            inf.onload=function(){
                inf.src='http://www.test.com/b.html'       //iframe加载完成,加载www.test.com域下边的空白页b.html
                console.log(inf.contentWindow.name)        //输出window.name中的数据
                body.removeChild(inf)                      //清除iframe
            }
        }
</script>

www.domain.com下b.html页:

<script>
        var str=window.location.href.substr(-1,1);      //获取url中携带的参数值
        $.ajax({
            type:"get",
            url:"http://www.domain.com/a.php"+"?m="+str, //通过ajax将查询参数传给php页面
            async:true,
            success:function(res){
                window.name=res                         //将接收到的查询数据赋值给window.name
            },
            error:function(){
                window.name='error'                      //..
            }
        });
</script>

window.postMessage方法来跨域:
www.test.com下a.html页:

<script>
        /*
        * window.postMessage是html5中的方法
        * */
        window.onload = function () {
            var oInput = document.getElementById('input1');
            var oButton = document.getElementById('btn1');
            oButton.onclick = function () {
                var data = oInput.value;
                window.frames[0].postMessage(data, '*');
            }
        }
</script>
<iframe src="http://www.lamport.me/data2.html" style="display:none" frameborder="0"></iframe>
<button id="btn1">点击我通过iframe框架向http://www.lamport.me/data2.html页面发送并返回数据</button>

www.domain.com下b.html页:

<script>
    window.onmessage = function(e) {
        e = e || event;
        alert('我接受到来自外太空的数据:' + e.data);
    }
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值