ajax跨域问题我只学一种解决方案

3,305 阅读4分钟

Ajax跨域问题的jsonp解决方案

在前端我们经常会使用Ajax来向服务器发送请求和接收服务器响应回来的数据,一般来说在同一个服务器的数据来往是没有什么问题的,但是有时使用Ajax请求数据并不局限于同一个服务器,跨服务器请求就会遇到跨域问题,下面我们探讨一下跨域问题是怎么产生的,最优的解决方案是什么?

同源策略

同源策略是浏览器的一种安全策略,是为了保护本地数据不被从其他服务器获取回来的数据污染,从而拒绝接受非本服务器响应回来的数据.这样的后果就是我们能成功的向其他的服务器发送数据请求,对方也能成功响应并返回数据,

但是,就是没有办法接受数据,因为浏览器拦截了.

这里解释一下"同源"的概念:

协议,域名,端口都一致视为同源,有其中一个不同则为不同源

跨域问题

上面已经解释了什么是同源,可以理解为同源即同域,如果在非同源的基础上,想要进行数据来往,这时就会出现我们所说的跨域问题

怎么解决Ajax的跨域问题

一共有六种方案:

  • jsonp
  • document.domain+iframe
  • document.hash+iframe
  • window.name+iframe
  • window.postMessage
  • flash等第三方插件

注意:我下面要讲的解决方案是jsonp,在讲jsonp之前我先讲基础的同源的jQuery的Ajax的写法

同源的jQuery的Ajax的实现

1.环境

phpstudy

2.目录结构

3.index.html文件
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
	</head>
	<body>
		<button class="btn">获取数据</button>
		<script type="text/javascript">
		$(function() {
			$(".btn").click(function() {
				$.ajax({
					type: "get",
					url: "./data.php",
					dataType:"json",
					success: function(data) {
						//var data=JSON.parse(data);
						console.log(data.username);//zhangsan
						console.log(data.age);//12
					},
					error: function() {
						console.log("获取失败");
					}
				});
			})
		})
		</script>
	</body>
</html>

4.data.php文件
<?php
	$arr=["username"=>"zhangsan","age"=>12];
	echo json_encode($arr);
?>

运行结果

注意:

  • 上面的代码在同源的情况下能够成功请求到data.php,并成功打印出数据

  • //jQuery中一般不需要json数组转化为对象,只需要指定数据的类型是json类型即可
    dataType:"json"//默认为文本型
    

跨域的jQuery的Ajax

为了实现Ajax的跨域请求,需要将上面例子的基础上,将index.html文件中Ajax请求的路径改为不同域名的网站,我在phpstudy环境中映射了一个目录并指定一个域名,下面的例子我们就来跨域访问该目录下的data.php文件

修改index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
	</head>
	<body>
		<button class="btn">获取数据</button>
		<script type="text/javascript">
		$(function() {
			$(".btn").click(function() {
				$.ajax({
					type: "get",
					url: "http://www.web2.com/data.php",
					dataType:"json",
					success: function(data) {
						//var data=JSON.parse(data);
						console.log(data.username);//zhangsan
						console.log(data.age);//12
					},
					error: function() {
						console.log("获取失败");
					}
				});
			})
		})
		</script>
	</body>
</html>

data.php文件

<?php
	$arr=["username"=>"zhangsan","age"=>12];
	echo json_encode($arr);
?>

运行结果

从上面的结果来看,跨域请求数据成功,对方响应也成功了,但是被浏览器拦截了,这就是典型的跨域问题

下面我们来解决这个问题,并能在前台成功读取返回来的值

JSONP的实现

jsonp这种解决跨域问题方案一共有两种方法

  • 静态script标签的src属性进行跨域请求
  • 动态创建script标签,通过标签的src属性进行跨域请求
静态script标签的src属性进行跨域请求

在前端的页面中将跨域的请求的URL赋值给script标签的src属性

<script src="http://www.web2.com/data.php"></script>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
	</head>
	<body>
		<button class="btn">获取数据</button>
		<script src="http://www.web2.com/data.php"></script>
		<script type="text/javascript">
		$(function() {
			$(".btn").click(function() {
				console.log(temp);
			})
		})
		</script>
	</body>
</html>

data.php

<?php
	//echo "var temp=111";//传单个值
	$arr=["username"=>"zhangsan","age"=>12];//项目中常常传数组
	$arr=json_encode($arr);
	echo "var temp=".$arr;
?>

不难发现这种传值的方式有些麻烦,下面介绍动态创建script标签,通过标签的src属性进行跨域请求

动态创建script标签,通过标签的src属性进行跨域请求

原生js写法

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
	</head>
	<body>
		<script type="text/javascript">
			//动态创建
			var script=document.createElement("script");
			script.src="http://www.web2.com/data.php?callback=gdata";
			var head=document.getElementsByTagName('head')[0];
			head.appendChild(script);
			
			function gdata(data){
				console.log(data.username);
				console.log(data.age);
			}
		</script>
	</body>
</html>

data.php

<?php
	$arr=["username"=>"zhangsan","age"=>12];
	$arr=json_encode($arr);
	$cb=$_GET['callback'];
	echo $cb.'('.$arr.')';//调用回调函数,注意拼接的方式,
?>

注意: 在上面的这种方法中,回调函数名字默认是callback,JQuery官方文档有说明,当然也可以是其他名字,这个名字由后台人员定义,再告诉前端人员,否则前端人员将无法使用正确的回调函数名获取值 我们知道,在实际的项目中,我们经常使用的是jQuery的写法

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
	</head>
	<body>
		<button class="btn">获取数据</button>
		<script type="text/javascript">
		$(function() {
			$(".btn").click(function() {
				$.ajax({
					type: "get",
					url: "http://www.web2.com/data.php",
					dataType:"jsonp",//注意类型为jsonp
					success: function(data) {
						console.log(data.username);//zhangsan
						console.log(data.age);//12
					},
					error: function() {
						console.log("获取失败");
					}
				});
			})
		})
		</script>
	</body>
</html>

到此为止,我们就讲完了Ajax跨域请求的jsonp解决方案,但是在实际的调用别人的api时还会有其他要注意的问题,比如需要在发送请求时同时将使用api的密钥发送过去