zoukankan      html  css  js  c++  java
  • 什么是跨域?解决跨域的六种方法。

    一、什么是跨域?

    跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对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脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。

    你可以理解为两个域名之间不能跨过域名来发送请求或者请求数据,否则就是不安全的,这种不安全也就是CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。

    一张图解释什么是CSRF

     二、解决跨域6种办法:

    2.1 JSONP:

    使用方式就不赘述了,但是要注意JSONP只支持GET请求,不支持POST请求。

    2.2 代理:

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

    2.3 PHP端修改header(XHR2方式)

    在php接口脚本中加入以下两句即可:

    header('Access-Control-Allow-Origin:*');//允许所有来源访问

    header('Access-Control-Allow-Method:POST,GET');//允许访问的方式

    2.4 iframe

    所以跨域通信其实很简单,在iframe和主页里都不断地检测hashtag有没有变化,一旦有变化,就做出相应的改变。

    setInterval(function() {
        var hashVal = window.location.hash.substr(1);
        document.body.style.backgroundColor = hashVal;
    }, 1000); 

     这么做的问题就是,需要不断地去检测hashtag是否改变,效率有点低,如果能通过原生的监听来实现,就会更加高效和优雅。这里就涉及到另一个iframe特性:可以设置其他iframe的大小,即使是不同域的。而页面的resize事件是可以监听的,所以就有了下面这个模型。

    主页面先把消息附加到hashtag,然后改变一个隐藏的(或者页面外的)iframe的size。这个iframe会监听resize事件,同时捕获到hashtag。捕获到hashtag后(也就是所需的数据),再对hashtag做进一步的处理。处理完后把数据传到主页内的一个iframe,或者直接操作该iframe。这样就比较优雅地完成了跨域操作。

    Demo

    将以下代码拷贝到本地的一个html文件,然后双击在浏览器中打开,看看能不能查单词。(ajax无法跨协议,这是iframe比ajax强大的地方)

    <!DOCTYPE html>
    <html>
        <head>
            <meta http-equiv="content-type" content="text/html;charset=utf-8" />
            <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
            <script>
                $(function(){
                    $('#btn').click(function(){
                        $proxy = $('#proxy');
                        var src = $proxy.attr('src').split('#')[0];
                        $proxy.attr('src', src + '#' + $('input[name=it]').val());
                        $proxy.css('width', $proxy.width()+1+'px');
                    });
                });
            </script>
        </head>
        <body>
    
            <input type="text" name="it"> <button id="btn">Translate</button>
            <p></p>
            <iframe src="http://demo.leezhong.com/crossdomain/proxy.html" name="proxy" id="proxy" style="position:absolute; top:-10px; 1px; height:1px"></iframe>
            <iframe src="http://demo.leezhong.com/crossdomain/show.html" name="show" id="show" style="60%;height:300px"></iframe>
        </body>
    </html>

    2.5 通过 window.name 实现跨域

    这篇文章是对 JavaScript跨域总结与解决办法 的补充。

    有三个页面:

    • a.com/app.html:应用页面。
    • a.com/proxy.html:代理文件,一般是一个没有任何内容的html文件,需要和应用页面在同一域下。
    • b.com/data.html:应用页面需要获取数据的页面,可称为数据页面。

    实现起来基本步骤如下:

    1、在应用页面(a.com/app.html)中创建一个iframe,把其src指向数据页面(b.com/data.html)。
    数据页面会把数据附加到这个iframe的window.name上,data.html代码如下:

    <script type="text/javascript">
        window.name = 'I was there!';    // 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右
                                         // 数据格式可以自定义,如json、字符串
    </script>

     2、在应用页面(a.com/app.html)中监听iframe的onload事件,在此事件中设置这个iframe的src指向本地域的代理文件(代理文件和应用页面在同一域下,所以可以相互通信)。app.html部分代码如下:

    <script type="text/javascript">
        var state = 0, 
        iframe = document.createElement('iframe'),
        loadfn = function() {
            if (state === 1) {
                var data = iframe.contentWindow.name;    // 读取数据
                alert(data);    //弹出'I was there!'
            } else if (state === 0) {
                state = 1;
                iframe.contentWindow.location = "http://a.com/proxy.html";    // 设置的代理文件
            }  
        };
        iframe.src = 'http://b.com/data.html';
        if (iframe.attachEvent) {
            iframe.attachEvent('onload', loadfn);
        } else {
            iframe.onload  = loadfn;
        }
        document.body.appendChild(iframe);
    </script>

    3、获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)。

    <script type="text/javascript">
        iframe.contentWindow.document.write('');
        iframe.contentWindow.close();
        document.body.removeChild(iframe);
    </script>

    总结起来即:iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

    2.6 HTML5中最炫酷的API之一(window.postMessage)

    就是  跨文档消息传输Cross Document Messaging。高级浏览器Internet Explorer 8+, chrome,Firefox , Opera  和 Safari 都将支持这个功能。这个功能实现也非常简单主要包括接受信息的”message”事件和发送消息的”postMessage”方法。

  • 相关阅读:
    关于在elasticSearch中使用聚合查询后只显示10个bucket的问题
    关于gradle与maven对springboot项目的配置文件加载异同
    正则表达式限制输入框只能输入数字
    关于在layui中的table checkbox 默认选中设置
    获取的ajax方法return的返回值的问题解析
    centos 6.5 安装mysql 5.6.35–libc.so.6(GLIBC_2.14)(64bit),libstdc++.so.6(GLIBCXX_3.4.15)(64bit)
    Linux下ps -ef和ps aux的区别及格式详解
    SSH 远程上传本地文件至服务器
    VMWare Fusion 8 序列号
    Mac OS X下安装和配置Maven
  • 原文地址:https://www.cnblogs.com/forever521Lee/p/9910484.html
Copyright © 2011-2022 走看看