JS跨域请求

1. 同源策略

        所有的浏览器都遵守同源策略,这个策略能够保证一个源的动态脚本不能读取或操作其他源的http响应和cookie,这就使浏览器隔离了来自不同源的内 容,防止它们互相操作。所谓同源是指协议、域名和端口都一致的情况。举例来说,首先在Nginx上配置两个虚拟主机,一个监听80端口,另一个监听81端 口:

server {  
        listen 80;  
        server_name localhost;  
          
        location / {  
            root   D:/dev/workspace;  
                    index  index.html index.htm;  
        }  
          
        location ~ \.php$ {  
            # 委托给后端的php  
            }  
    }

81端口的server配置是类似的,只是端口不同而已,所以通过80和81端口会访问到相同的东西。写两个php,一个是用于页面展示的show_person.php,另一个是用于生成json数据的person.php。

// show_person.php  
  
<html>  
    <head>  
        <script type="text/javascript" src="js/jquery.min.js"></script>  
        <script type="text/javascript">  
            function sayHello(person){  
                alert(person.name + ‘, your age is ‘ + person.age);  
            }  
           // 通过jQuery的ajax请求person.php的数据  
            $.getJSON(‘http://localhost:80/MongoTest/person.php‘, function(data){  
                sayHello(data);  
            });  
        </script>  
    </head>  
    <body>  
    </body>  
</html>
// person.php  
  
<?php  
$person = array(‘name‘ => ‘kobe‘, ‘age‘ => 34);  
echo json_encode($person);  
?>


  注意show_person.php中通过jQuery的getJSON请求http://localhost:80/MongoTest/person.php,这里是80端口。

然后先访问80端口试试,键入url:http://localhost/cross_domain/show_person.php。会弹出对话框,显示:kobe, your age is 34。

        然后再访问81端口,http://localhost:81/cross_domain/show_person.php,结果出错:

XMLHttpRequest cannot loadhttp://localhost/MongoTest/person.php. Origin http://localhost:81 is not allowed by Access-Control-Allow-Origin.
        这就是同源策略作用的效果。因为浏览器中访问的是81端口的内容,而show_person.php中请求的是80端口,所以请求的是不同源的内容,浏览器直接阻止这次请求。

2. 打破同源策略的限制

        浏览器会阻止ajax请求非同源的内容,但没有限制<script>标签来访问非同源的内容,也没有限制使用动态添 加<script>标签,所以可以采用这种方式打破这种限制。先测试下<script>访问非同源的内容,修改 show_person.php,如下:

// show_person.php  
  
<html>  
    <head>  
        <script type="text/javascript" src="js/jquery.min.js"></script>  
        <script type="text/javascript">  
            function sayHello(person){  
                alert(person.name + ‘, your age is ‘ + person.age);  
            }  
        </script>  
          
        <script type="text/javascript" src="http://localhost:80/MongoTest/person.php" ></script>  
    </head>  
    <body>  
    </body>  
</html>

  还需要对person.php略微修改,以实现函数调用:

// person.php  
  
<?php  
$person = array(‘name‘ => ‘kobe‘, ‘age‘ => 34);  
echo ‘sayHello(‘.json_encode($person).‘)‘;  
?>

实际上,通过<script>标签就是将远程请求来的数据插入到<script></script>之间。访问80和81端口,都会得到希望得到的结果:kobe, your age is 34。

        下面就看一下,动态添加<script>标签实现跨域请求数据。修改show_person.php:

// show_person.php  
  
<html>  
    <head>  
        <script type="text/javascript" src="js/jquery.min.js"></script>  
        <script type="text/javascript">  
            function sayHello(person){  
                alert(person.name + ‘, your age is ‘ + person.age);  
            }  
                // 通过callback参数指定回调函数  
            var url = ‘http://localhost:80/MongoTest/person.php?callback=sayHello‘;  
            var script = document.createElement(‘script‘);  
            script.setAttribute(‘src‘, url);  
            document.getElementsByTagName(‘head‘)[0].appendChild(script);   
        </script>  
    </head>  
    <body>  
    </body>  
</html>

person.php再做修改:

// person.php  
  
<?php  
$person = array(‘name‘ => ‘kobe‘, ‘age‘ => 34);  
echo $_REQUEST[‘callback‘].‘(‘.json_encode($person).‘)‘;  
?>

通过81端口访问,发现也会打印出结果。这就实现了跨域请求,可以通过firefox的firebug或者chrome的js控制台查看html元素发现,在head元素上多了一个<script>元素

<script src="http://localhost:80/MongoTest/person.php?callback=sayHello"></script>

3. JSONP

        实际上,上面的例子就是一个JSONP的简单实现。JSONP(JSON with Padding)就是服务器端和客户端互相协作以完成跨域请求的一种协议,客户端向服务器端发送请求并附带callback函数,服务器端返回相应的js 代码,这个代码就是执行回调函数,参数就是服务器端返回的JSON数据。上面例子中的person.php就是服务端的简单实现,返回的响应内容是sayHello({"name":"kobe","age":34}),这段内容会被客户端插入到动态生成的script标签内部。

        客户端在发起跨域请求时,需要制定具体的回调函数,比如这个请求http://localhost:80/MongoTest /person.php?callback=sayHello,callback就是回调函数,服务器端也要通过callback要提取回调函数名,所以 具体的这个参数需要客户端和服务器端达成一致,否则不能实现跨域。

        在jQuery中拥有对JSONP的支持,只要在使用jQuery.getJSON方法时传入的url的格式是url?callback=?即可,jQuery会自动的将?替换成具体的回调函数名。上面例子的功能,可以采用jQuery改写成:

$.getJSON(‘http://localhost:80/MongoTest/person.php?callback=?‘, function(data){  
    sayHello(data);  
});

 访问81端口,可以得到正确的响应。观察一下,发现person.php的响应内容是:

 jQuery17103600438670255244_1331202380099({"name":"kobe","age":34})

        前面的jQuery17103600438670255244_1331202380099就是jQuery动态生成的回调函数名,然后在这个回调函数内 容调用后面定义的匿名函数,并将得到的JSON数据传进去。jQuery可以优化JSONP请求,如果向同一个源发出请求,jQuery 就将其转化为普通 Ajax 请求。


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。