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的密钥发送过去