什么是跨域问题?
简单来说就是前台调用后端服务接口的时候,如果这个接口不是同一个域的,就会产生跨域问题。由其是前后端分离的项目中很常见。
演示跨域问题
编写后台代码
新建后台工程:
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/get1")
public String get1(){
System.out.println("------------------------------------TestController");
return "get1 ok----------";
}
}
编写前台代码
新建前台功能:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="jquery-1.4.2.min.js"></script>
</head>
<body>
<a href="#" onclick="get1()">发送get1请求</a>
<script>
function get1(){
$.getJSON("http://localhost:8080/test/get1").then(
function (result) {
console.log(result);
}
);
}
</script>
</body>
</html>
启动两个工程,访问:http://localhost:8081/#
上面的报错信息就是跨区问题。
为了后续测试方便,编写测试代码(引入Jasmine测试框架)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" type="text/css" href="jasmine-3.2.0/jasmine.css" />
<script src="jquery.js"></script>
<script src="jasmine-3.2.0/jasmine.js"></script>
<script src="jasmine-3.2.0/jasmine-html.js"></script>
<script src="jasmine-3.2.0/boot.js"></script>
</head>
<body>
<script>
//每一个测试用例的超时时间
jasmine.DEFAULT_TIMEOUT_INTERVAL=1000;
//请求的接口的前缀
var base = "http://localhost:8080/test";
//测试模块
describe("ajax跨域",function () {
//测试方法
it('get1请求', function (done) {
//服务器的返回结果
var result;
$.getJSON(base + "/get1").then(function (jsonObj) {
result = jsonObj;
})
//由于是异步请求,需要使用setTimeout来检验
setTimeout(function () {
expect(result).toEqual({
"data":"get1 ok"
})
})
//检验完成,通知jasmine框架
done();
},100);
});
</script>
</body>
</html>
访问http://localhost:8081/index.html ,因为跨域返回undefined和预期返回的结果“get1 ok”不一致。
为什么会发生AJAX跨域?
1、浏览器限制 (从上面后台打印的结果和浏览器返回结果可以看出,其实结果已经到后来了)
2、跨域(域名、端口一个不一样)
3、发出去的是XHR(XMLHttpRequest)请求(用图片或者script方式就不会有跨域问题)
<script src="http://localhost:8080/test/get1"></script>
<img src="http://localhost:8080/test/get1" alt="" />
怎么解决跨域问题(从上面说的3个方面解决)
1、用命令行参数方式启动浏览器禁止检查(从前端的方面去解决)
2、使用JSONP解决跨域,利用script标签请求资源可以跨域来解决跨域问题的。是一种变通的解决方案。非官方协议,是一种约定。
问题:那使用JSONP需要改动后台代码吗?(需要的)
用JSONP的发请求的时候会自动加了一个callback的参数,后台发现callback参数就会知道这是个jsonp请求,就会把返回的JS格式转换成JSON格式(这个后台要写配置代码)。callback生成的值就是需要返回的函数名,而返回的数据就是参数,这就是JSONP实现原理。
除了allback参数还会生成一个参数,这个随机参数是为了防止浏览器缓存的。
JSONP有什么弊端:1、服务器需要改动代码支持(因为如果调用的是别的人就没法改了)2、只支持给方法 3、发送的不是XHR请求(XHR有很多特性:异步等等)
跨域解决方向
1、被调用方解决(基本HTTP协议关于跨域方面的规定,在响应头里面增加指定的字段,告诉浏览器,我允许它调用,这种解决方案是直接从浏览器发送过去的)
2、调用方解决(基于隐藏跨域的思路,这种解决方式请求不会从浏览器直接发送到被调用方,而是从中间的HTTP服务器转发过去的,举个例子假设有调用方a.com和被调用方b.com,第一种解决方案你会在浏览器上面会看到有b.com的url,但第二种看到的都是a.com的url)