前端跨域调用–JSONP
标签(空格分隔): 淘淘商城
之前一直比较关注后端的RPC组件,支持跨系统之间的调用,对于前端的调用,只对Ajax请求有印象,但Ajax是不能跨域调用的。这边就要使用JsonP技术,其实JsonP谈不上是一个新技术,只是一个跨域请求的解决方案,利用了JavaScript的一个漏洞来完成跨域请求。
首先说下什么是跨域调用:
- 域名不同
- 域名相同,端口不同
JsonP的原理
在前端开发中,页面都会引入很多js、css静态文件,也可以在线引入一些其他网站的静态资源,域名和我们所在域名不一样,但不影响使用,说明网页对静态资源的跨域请求是没问题的。但是在Ajax请求发送请求之后,服务端也是可以正常的接收请求并作出相应。如下图所示:
客户端代码:
$.ajax({
url : "http://sso.taotao.com/service/user/query/" + _ticket,
type : "GET",
success : function(data){
if(data){
var _data = data;
var html =_data.username+",欢迎来到淘淘!<a href=\"http://www.taotao.com/user/logout.html\" class=\"link-logout\">[退出]</a>";
$("#loginbar").html(html);
}
}
});
在浏览器的“NetWork”中找到:http://sso.taotao.com/service/user/query/这个请求,发现相应状态为:200,但控制台报错:
Failed to load http://sso.taotao.com/service/user/query/c823e36c0a20cff4ab5a3b3ac20669a6: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://www.taotao.com' is therefore not allowed access.
原因是:服务端不管你请求的来源,只管相应,但是当数据经过浏览器的时候,浏览器判断出js访问的数据来源不同的域,于是便拒绝将数据返回到页面中,所以报上面的错。请求如下图所示:
那如何解决这个问题呢?我们先看一个例子:
1、在jsp中返回一个json数据,然后在另外一个页面中请求:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
out.print("{\"abc\":123}");
%>
前端访问代码为:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="http://static.taotao.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<title></title>
</head>
<script>
alert($);
$(function(){$.ajax({
url :"http://manager.taotao.com/rest/page/jsonp",
dataType:"json",
type : "GET",
success : function(data){
alert(data.abc);
}
})
});
</script>
<body>
</body>
</html>
结果:
alert($)可以正常输出,但是ajax请求报错,错误信息和上面的一模一样,出现了跨域问题:
Failed to load http://manager.taotao.com/rest/page/jsonp: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
**结论:scprit标签的src可以支持跨域资源,但是ajax不可以出现跨域。
思路:可否借助script标签来进行加载数据呢?—可以的**
2、修改jsp代码如下:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="http://static.taotao.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<title></title>
</head>
<script>
alert($);
/*$(function(){$.ajax({
url :"http://manager.taotao.com/rest/page/jsonp",
dataType:"json",
type : "GET",
success : function(data){
alert(data.abc);
}
})
});*/
</script>
<script type="text/javascript" src="http://manager.taotao.com/rest/page/jsonp"></script>
<body>
**结果:请求资源可以正常请求,但是js解析出错。
原因:scpript加载资源后,会对资源进行js解析,但是我们返回的不是js而是json数据
解决:只需要把返回的数据封装成js就行了。**
3、将后台返回的数据封装成js即可。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
out.print("fun({\"abc\":123});");
%>
测试结果:
报错:Uncaught ReferenceError: fun is not defined
at jsonp:2
这个错误就比较清楚了,表示:fun方法没有定义,那我们在页面上定义一个方法:
function fun(data){
alert(data.abc);
}
</script>
<script type="text/javascript" src="http://manager.taotao.com/rest/page/jsonp"></script>
测试结果:可以正常弹出
**结论:1、jsonp通过script标签的src可以跨域请求的特性加载资源
2、将加载的资源当做一个js脚本解析(通过一个方法名将数据进行包裹)
3、定义一个函数作为回调函数,获取传入的数据**
JsonP怎么解决这个问题呢?
综合上面的原理,我们就可以使用如下方式,先看图:
步骤:1、通过script发起资源请求,请求中声明回调函数的方法名
2、定义回调函数
3、服务端处理之后,返回一个将回调函数包装之后的符合js语法的字符串。
—– 这样就解决了前端跨域请求的问题了