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 请求。
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页