Loading

AJAX跨域

一、相关概念

  • 同源策略:是浏览器的一种安全策略,所谓同源是指域名、协议、端口完全相同,只有同源的地址才可以相互通过AJAX的方式请求
  • 跨域请求:不同源地址之间的访问就是跨域请求

二、问题以及尝试解决

①AJAX

  • 不同源地址之间,默认不能相互发送AJAX请求,执行后,浏览器会报错,大意是说localhost域名无法向google.com域名请求数据。
  • 因为同源策略的限制,不同域名、协议(http、https)或者端口无法直接进行ajax请求。 同源策略只针对于浏览器端,浏览器一旦检测到请求的结果的域名不一致后,会堵塞请求结果。
  • 这里注意,跨域请求是可以发去的,但是请求响应response被浏览器堵塞了
  <script>
       /**
        * 当前页面访问地址:http://localhost/test.html
        * 希望请求地址:https://www.baidu.com/s?wd=%E8%B7%A8%E5%9F%9F&tn=93338132_hao_pg(百度搜索跨域)
        */
        var url='https://www.baidu.com/s?wd=%E8%B7%A8%E5%9F%9F&tn=93338132_hao_pg';
        $.get(url,function(res){
            console.log(res);
        })
    </script>

②img 可以发送不同源之间的请求,但是无法拿到响应结果

<script>
       /**
        * 当前页面访问地址:http://localhost/test.html
        * 希望请求地址:https://www.baidu.com/s?wd=%E8%B7%A8%E5%9F%9F&tn=93338132_hao_pg(百度搜索跨域)
        */
        var url='https://www.baidu.com/s?wd=%E8%B7%A8%E5%9F%9F&tn=93338132_hao_pg';
        var img=new Image();
        img.src=url;
    </script>

③link 可以发送不同源之间的请求,但是无法拿到响应结果

    <script>
       /**
        * 当前页面访问地址:http://localhost/test.html
        * 希望请求地址:https://www.baidu.com/s?wd=%E8%B7%A8%E5%9F%9F&tn=93338132_hao_pg(百度搜索跨域)
        */
        var url='https://www.baidu.com/s?wd=%E8%B7%A8%E5%9F%9F&tn=93338132_hao_pg';
        var link=document.createElement('link');
        link.rel= 'stylesheet';//注意:link的真正含义是链入一个文档,通过rel属性申明链入文档与当前文档之间的关系
        link.href=url;
        document.body.appendChild(link);
    </script>

④script  可以发送不同源之间的请求,但是无法拿到响应结果,但是借助服务端,可以拿到数据作为js文件执行,这就是JSONP的原理

三、JSONP解决方案

①概念:JSONP 是JSON with Padding的缩写,是一种借助于script标签发送跨域请求的技巧

②原理:在客户端借助script标签请求服务端的一个动态网页(php文件),服务端的这个动态网页返回一段带有函数调用的JavaScript全局函数调用的脚本,并将原来需要返回给客户端的数据传递进去

③案例实现(封装):

<?php
    //从本地的MySQL数据库test中读取数据(表users)
    $conn=mysqli_connect('localhost','root','0000','test');
    $query=mysqli_query($conn,'select * from users');
    while($row=mysqli_fetch_assoc($query)){
        $data[]=$row;
    }
    //如果没有参数,以json格式返回这个数据
    if(empty($_GET['callback'])){
        header('Content-Type: application/json');
        echo json_encode($data);
        exit();
    }
    //申明数据类型是js文件
    header('Content-Type: application/javascript');
    $result=json_encode($data);
    
    //$_GET['callback]}为get方式通过问号传递过来的参数,即函数名
    $callback_name=$_GET['callback'];
    echo "{$callback_name}({$result})";
?>
<script>
       /**
        * 当前页面访问地址:http://www.demo.me/test.html(通过虚拟主机配置www.demo.me域名)
        * 希望请求地址:http://www.test.me/test.php(通过虚拟主机配置www.test.me域名)
        */
       //封装jsonp函数
        function jsonp(url,params,callback){
            var funcName='jsonp_'+Date.now()+Math.random().toString().substr(2,5);
            if(typeof params==='object'){
                var tempArr=[];
                for(var key in params){
                    var value=params[key];
                    tempArr.push(key + "=" + value);
                }
                params = tempArr.join('&');
            }
            var script=document.createElement("script");
            script.src=url + '?' + params  +'&callback=' + funcName ;
            document.body.appendChild(script);
            window[funcName]=function(data){
                callback(data);
                document.body.removeChild(script);
            }
        }
    //调用jsonp函数
    jsonp('http://www.test.me/test.php',{id:1},function(res){
        console.log(res);
    })
    </script>

④总结:由于XMLHttpRequest无法发送不同源之间的跨域请求,所以找到一种通过script标签发送跨域请求的方案,这种方案就是JSONP,JSONP需要服务端的配合,服务端按照客户端的要求返回一段JavaScript调用客户端的函数,只能发送GET请求,因为JSONP用的是script标签,跟AJAX提供的XMLHttpRequest没有任何的关系

⑤jQuery中使用JSONP

    <script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
    <script>
       /**
        * 当前页面访问地址:http://www.demo.me/test.html(通过虚拟主机配置www.demo.me域名)
        * 希望请求地址:http://www.test.me/test.php(通过虚拟主机配置www.test.me域名)
        */
       //jquery中使用JSONP就是将dataType设置为jsonp
        $.ajax({
            url: 'http://www.test.me/test.php',
            dataType: 'jsonp',
            success: function(res){
                console.log(res)
            }
        })
    </script>

⑥其他AJAX封装库: Axios

五、CORS(Cross Origin Resource Share)解决方案

①用法:这种方法无需客户端做出任何变化(客户端不用改代码),只要在被请求的服务器响应的时候添加一个的响应头,表示这个资源是否允许指定域请求

 header('Access-Control-Allow-Origin: *')

②案例实现

<?php
    //从本地的MySQL数据库test中读取数据(表users)
    $conn=mysqli_connect('localhost','root','0000','test');
    $query=mysqli_query($conn,'select * from users');
    while($row=mysqli_fetch_assoc($query)){
        $data[]=$row;
    }
    //==============================================
    header('Access-Control-Allow-Origin: *');
    //==============================================
    header('Content-Type: application/json');
    echo json_encode($data);
?>
    <script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
    <script>
       /**
        * 当前页面访问地址:http://www.demo.me/test.html(通过虚拟主机配置www.demo.me域名)
        * 希望请求地址:http://www.test.me/test.php(通过虚拟主机配置www.test.me域名)
        */
        $.get('http://www.test.me/test.php',{},function(res){
            console.log(res);
        })
    </script>

 

posted @ 2018-06-27 02:01  澎湃_L  阅读(145)  评论(0编辑  收藏  举报