• JavaScript跨域


    只要协议、域名、端口有任何一个不同,都被当作是不同的域。

    也就是“http://www.baidu.com”这个URL首部,必须完全一样才能互相通信。

    这个也叫同源策略,当前域名的js只能读取/修改同域下的窗口属性

    为什么要有同源策略?为了防止CSRF攻击,保证来至不同源的对象不会互相干扰。

    一、通过jsonp跨域(实际上是动态创建script标签)

    原理:不同的域可以传输JS文件

    服务器的data.php:

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

    本地的HTML:

    
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
    <script>
        function dosomething(jsondata){
            console.log(jsondata)
        }
    </script>
    <script src='http://www.a.com/data.php?callback=dosomething'></script>
    </body>
    </html>

    或者用jquery:

    
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <script src="http://cdn.static.runoob.com/libs/jquery/1.8.3/jquery.js"></script>  
    </head>
    <body>
    <script>
    $.getJSON("http://www.a.com/data.php?callback=?"function(jsondata) {
        console.log(jsondata);
    });
    </script>
    </body>
    </html>

    结果:

    ["a","b","c"]

    JSONP的优点是:1.它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;

             2.它的兼容性更好,在更加古老的浏览器中都 可以运行,不需要XMLHttpRequest或ActiveX的支持;

            3.在请求完毕后可以通过调用callback的方式回传结果。

    JSONP的缺点是:1.它只支持GET请求而不支持POST等其它类型的HTTP请求;

            2.它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JS调用的问题。

            3.jsonp在调用失败的时候不会返回各种HTTP状态码。

            4.安全性欠缺。

    2、通过document.domain+ iframe (只有在主域相同的时候才能使用该方法)

    两个不同域的a.html和b.html

    在www.a.com/a.html中:

    
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>a跨域</title> 
    </head>
    <body>
    <script>
    function onLoad(){
        var iframe=document.getElementById('iframe');
        var win=iframe.contentWindow;//能读取iframe里的window对象
        var doc=win.document;//无法读取,报错
        var name=win.name;//无法读取,报错
    }
    </script>
    <iframe id="iframe" src="http://www.a.com/b.html" onload="onLoad()"></iframe>
    </body>
    </html>

    在www.script.a.com/b.html中:

    
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>b跨域</title>  
    </head>
    <body>
    <div>内容</div>
    </body>
    </html>

    解决办法:在两个页面都插入document.domain,这样就能访问iframe里window对象的各种属性。

    
    
    <script>
        document.domain='a.com';//设置成主域
    </script>

    3、使用window.name来进行跨域

    原理:在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限

    同一目录下的a.html和b.html

    a.html

    
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>a跨域</title> 
    </head>
    <body>
    <script>
    window.name='页面a设置的值';
    setTimeout(function(){
        window.location='b.html'
    },3000);
    </script>
    </body>
    </html>
     

    b.html

    
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>b页面</title> 
    </head>
    <body>
    <script>
    alert(window.name);
    </script>
    </body>
    </html>

    a.html页面载入后3秒,跳转到了b.html页面,弹出“页面a设置的值”

    跨域:在b.html里设置window.name,a.html就能访问这个值了(。。。我未成功)

    4、使用HTML5的window.postMessage方法来跨域传送数据

     不同域的a.html和b.html

    a.html

    
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>a跨域</title> 
    </head>
    <body>
    <script>
    function onLoad(){
        var iframe=document.getElementById('iframe');
        var win=iframe.contentWindow;
        win.postMessage('来自a页面的信息','*');//第二个参数为想访问的域,*为通配
    }
    </script>
    <iframe id="iframe" src="http://www.a.com/b.html" onload="onLoad()"></iframe>
    </body>
    </html>

    b.html

    
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>b跨域</title> 
    </head>
    <body>
    <script>
    window.onmessage=function(e){
        e=e||event;
        alert(e.data);
    }
    </script>
    </body>
    </html>

    5.利用flash

    6.利用iframe和location.hash

    7.利用CORS

    CORS是自定义HTTP头部,使浏览器和服务器对比,从而决定请求和响应是否应该进行

    IE8使用XDR对象实现CORS,和XHR类似用法

    var xdr=new XDomainRequest();
    xdr.onload=function(){
    alert(xdr.responseText)
    };
    xdr.open('get',"http://www.a.com/");
    xdr.send(null)

    现代浏览器使用普通的XMLHttpRequest对象请求就行。

    8.图像Ping

    var img=newImage();
    img.onload=img.onerror=function(){
    alert('1');
    };
    img.src="http://www.a.com/test?name=aaa";

    缺点:1.只能GET  2.无法访问服务器的响应文本

    前面这几种方法,大部分都需要前后两端支持。如果单纯的前端实现跨域,可以使用代理。

    1.https://github.com/hongrunhui/node-proxy(未测试过)

    2.eezz.com (代理网站请求返回的数据有时候没刷新,可能是请求频率/次数受限制了?所以还是有点小问题)

    
    
      var requestUrl = "http://www.weather.com.cn/adat/sk/101110101.html";
      //这里一定要注意,实际请求的url其实是以参数形式从eezzo.com读取的,因此我们都要对url进行编码,使用encodeURI方法即可
      $.getJSON("http://eezzo.com/API/CD", { url: encodeURI(requestUrl) }, function(json) {
        console.log(json);
      });

    3.雅虎代理,同上

    <script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
    <script>
    var requestURL="http://www.weather.com.cn/adat/sk/101110101.html";
    $.getJSON("http://query.yahooapis.com/v1/public/yql", {
        q: "select * from json where url=""+requestURL+"""//请注意划线和两个引号
        format: "json"
    }, function(data) {
        if (data.query.results) {
            console.log(data.query.results.json);
        } else {
            console.log('no such code: ' + code);
        }
    });
    </script>

    4.原生代码实现jsonp跨域读取(动态创建script)

        var jsonp = function (url, callback) {
            if (typeof url === 'undefined') {
                throw 'the 1st param "url" missing';
            }
            if (typeof callback === 'undefined') {
                throw 'the 2nd param "callback" missing';
            }
            var jsonpcallback = 'callback' + new Date().valueOf();
            if (typeof callback !== 'string') {
                window[jsonpcallback] = callback;
                callback = jsonpcallback;
            } else {
                window[jsonpcallback] = function (data) {
                    eval(callback).call(window, data);
                }
            }
            var script = document.createElement('script');
            script.setAttribute('type', 'text/javascript');
            script.setAttribute('src', url + (url.indexOf('?') == -1 ? '?' : '&') + 'callback=' + jsonpcallback);
            var head = document.getElementsByTagName('head')[0];
            head.appendChild(script);
        };
     
        jsonp('https://api.douban.com/v2/movie/top250', function (data) {
            console.log(data);
        });

    简化版:

            var jsonp = (url, callback) => {
                var jsonpcallback = 'callback' + new Date().valueOf(); //随便写个字符串
                window[jsonpcallback] = callback; //再把传进来的callback暴露到全局,命名为上面的字符串
    
                var script = document.createElement('script'); //创建标签
                script.setAttribute('src', url + (url.indexOf('?') == -1 ? '?' : '&') + 'callback=' + jsonpcallback);
                document.getElementsByTagName('head')[0].appendChild(script); //标签插入头部
            };

    5.设置dataType为jsonp

        $.ajax({
            url: "https://api.douban.com/v2/movie/top250",
            dataType: 'jsonp',
            success: function (data) {
                console.log(data);
            }
        });
  • 相关阅读:
    UVa 11181
    UVa 10491
    UVa 1636
    UVa 1262
    UVa 10820
    UVa 1635
    UVa 12716
    [2019杭电多校第六场][hdu6635]Nonsense Time
    [2019杭电多校第五场][hdu6630]permutation 2
    [2019杭电多校第五场][hdu6629]string matching(扩展kmp)
  • 原文地址:https://www.cnblogs.com/shen076/p/6538473.html
Copyright © 2020-2023  润新知