跨域
在讲跨域之前,先介绍一个概念—同源策略。源(origin)指的是协议、域名、端口号,同源指的是在url中协议、域名、端口号均相同。那么同源策略是浏览器的一个安全功能,不同源的脚本在没有明确授权的情况下,不能读写对方资源。
跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制,那么只要协议、域名、端口有任何一个不同,都被当作是不同的域。
常见跨域场景
URL | 说明 | 是否允许通信 | |
---|---|---|---|
http://www.alibaba-inc.com/a.jshttp://www.alibaba-inc.com/b.js | 同一域名 | 允许通信 | |
http://www.alibaba-inc.com/a.jshttp://www.alihealth.com/a.js | 主域不同 | 跨域,不允许通信 | |
http://abc.alibaba-inc.com/a.jshttp://def.alibaba-inc.com/a.js | 子域不同 | 跨域,不允许通信 | |
http://www.alibaba-inc.com:8080/a.jshttp://www.alibaba-inc.com/a.js | 端口不同 | 跨域,不允许通信 | |
http://www.alibaba-inc.com/a.jshttps://www.alibaba-inc.com/a.js | 协议不同 | 跨域,不允许通信 |
模拟跨域失败场景
根据同源策略,在某个服务器下的界面是无法获取到该服务器以外的数据的,基于此我们通过中间件平台生成两个tddl demo,这两个demo分别对应的url为:http://localhost:7001以及http://localhost:8080。在端口为8080的服务中通过AJAX调用端口为7001的服务:向数据库中插入name为ajax123的一条记录。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
function loadXMLDoc()
{
var xmlhttp;
if (window.XMLHttpRequest)
{
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp=new XMLHttpRequest();
}
else
{
// IE6, IE5 浏览器执行代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","http://localhost:7001/mybatis/insert?name=ajx123",true);
xmlhttp.send();
}
</script>
</head>
<body>
<div id="myDiv"><h2>使用 AJAX 请求</h2></div>
<button type="button" onclick="loadXMLDoc()">请求</button>
</body>
</html>
上述程序在运行的时候会报如下的错误:
因此通过AJAX进行跨域时是没有权限进行访问的,此时我们从数据库中也不能查找到name为ajax123的记录。
AJAX跨域方案—JSONP
JSONP(JSON with Padding) 是JSON的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。
JSONP的基本原理是:在html页面中通过相应的标签从不同域名下加载静态资源文件是被浏览器允许的,所以我们可以通过这个“犯罪漏洞”来进行跨域。一般,允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。那么客户端的代码如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript">
var callFunction = function(data){
alert(data.id + " " + data.name);
};
</script>
</head>
<body>
<script src="http://localhost:7001/mybatis/name?callback=callFunction"></script>
</body>
</html>
相对应的服务端需要改写控制层相对应的方法:
@RequestMapping(value = "/mybatis/name", method = RequestMethod.GET)
public @ResponseBody String queryByMyBatis(String callback) {
Name queryResult = mybatisDemo.query();
Gson gson = new Gson();
return callback+"("+gson.toJson(queryResult)+")";
}
由此我们可以看到JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。
那么通过该方案最后运行结果会显示出查询数据库表单中的一条记录。
----