原文地址:
1. 同源策略
所有的浏览器都遵守同源策略,这个策略能够保证一个源的动态脚本不能读取或操作其他源的http响应和cookie,这就使浏览器隔离了来自不同源的内容,防止它们互相操作。所谓同源是指协议、域名和端口都一致的情况。举例来说,首先在Nginx上配置两个虚拟主机,一个监听80端口,另一个监听81端口:
[plain] view plain copy print ?
1. server {
2. listen 80;
3. server_name localhost;
4.
5. location / {
6. root D:/dev/workspace;
7. index index.html index.htm;
8. }
9.
10. location ~ \.php$ {
11. # 委托给后端的php
12. }
13. }
[php] view plain copy print ?
1. // show_person.php
2.
3. <html>
4. <head>
5. "text/javascript" src="js/jquery.min.js"></script>
6. "text/javascript">
7. function sayHello(person){
8. ', your age is ' + person.age);
9. }
10. // 通过jQuery的ajax请求person.php的数据
11. 'http://localhost:80/MongoTest/person.php', function(data){
12. sayHello(data);
13. });
14. </script>
15. </head>
16. <body>
17. </body>
18. </html>
[php] view plain copy print ?
1. // person.php
2.
3. <?php
4. $person = array('name' => 'kobe', 'age' => 34);
5. echo json_encode($person);
6. ?>
然后先访问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.
2. 打破同源策略的限制
浏览器会阻止ajax请求非同源的内容,但没有限制<script>标签来访问非同源的内容,也没有限制使用动态添加<script>标签,所以可以采用这种方式打破这种限制。先测试下<script>访问非同源的内容,修改show_person.php,如下:
[php] view plain copy print ?
1. // show_person.php
2.
3. <html>
4. <head>
5. "text/javascript" src="js/jquery.min.js"></script>
6. "text/javascript">
7. function sayHello(person){
8. ', your age is ' + person.age);
9. }
10. </script>
11.
12. "text/javascript" src="http://localhost:80/MongoTest/person.php" ></script>
13. </head>
14. <body>
15. </body>
16. </html>
[php] view plain copy print ?
1. // person.php
2.
3. <?php
4. $person = array('name' => 'kobe', 'age' => 34);
5. echo 'sayHello('.json_encode($person).')';
6. ?>
下面就看一下,动态添加<script>标签实现跨域请求数据。修改show_person.php:
[php] view plain copy print ?
1. // show_person.php
2.
3. <html>
4. <head>
5. "text/javascript" src="js/jquery.min.js"></script>
6. "text/javascript">
7. function sayHello(person){
8. ', your age is ' + person.age);
9. }
10. // 通过callback参数指定回调函数
11. var url = 'http://localhost:80/MongoTest/person.php?callback=sayHello';
12. var script = document.createElement('script');
13. 'src', url);
14. 'head')[0].appendChild(script);
15. </script>
16. </head>
17. <body>
18. </body>
19. </html>
[php] view plain copy print ?
1. // person.php
2.
3. <?php
4. $person = array('name' => 'kobe', 'age' => 34);
5. echo $_REQUEST['callback'].'('.json_encode($person).')';
6. ?>
通过81端口访问,发现也会打印出结果。这就实现了跨域请求,可以通过firefox的firebug或者chrome的js控制台查看html元素发现,在head元素上多了一个<script>元素
[html] view plain copy print ?
1. <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改写成:
[javascript] view plain copy print ?
1. $.getJSON('http://localhost:80/MongoTest/person.php?callback=?', function(data){
2. sayHello(data);
3. });
jQuery17103600438670255244_1331202380099({"name":"kobe","age":34})