SpringMVC解决跨域问题
有个朋友在写扇贝插件的时候遇到了跨域问题。
于是我对解决跨域问题的⽅式进⾏了⼀番探讨。
问题
API:查询单词
URL:
请求⽅式: GET
参数: {word}, 必须,要查询的单词
报错为
XMLHttpRequest cannot load localhost/home/saveCandidate. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status c 这就是典型的跨域问题。
但是我在浏览器⾥输⼊URL是可以进⾏查询单词的操作的,有什么不同,即下⾯两个问题
1. 为什么在浏览器地址栏输⼊URL不会出现跨域问题。
2. 不在服务器运⾏的html是否可以完成⼀次http请求
经过Google和⾃⼰测试
1. 跨域限制是浏览器⾏为,不是服务器⾏为。浏览器认为地址栏输⼊时安全的,所以不限制认为是跨域。
2. 可以,只要服务器配置为所有域都可以进⾏请求,那么不在服务器运⾏的HTML就可以完成http请求。
什么是跨域问题
同源策略:
同源指的是域名(或IP),协议,端⼝都相同,不同源的客户端脚本(javascript、ActionScript)在没明确授权的情况下,不能读写对⽅的资源。
URL解释是否跨域
原来的URL
⼦域名跨域(cookie也⽆法访问)
不加www跨域
更改协议跨域
更改端⼝号跨域
原因:
同源政策的⽬的,是为了保证⽤户信息的安全,防⽌恶意的⽹站窃取数据。
设想这样⼀种情况:A⽹站是⼀家银⾏,⽤户登录以后,⼜去浏览其他⽹站。如果其他⽹站可以读取A⽹站的Cookie,会发⽣什么?
很显然,如果Cookie包含隐私(⽐如存款总额),这些信息就会泄漏。更可怕的是,Cookie往往⽤来保存⽤户的登录状态,如果⽤户没有退出登录,其他⽹站就可以冒充⽤户,为所欲为。因为浏览器同
时还规定,提交表单不受同源政策的限制。
由此可见,"同源政策"是必需的,否则 Cookie 可以共享,互联⽹就毫⽆安全可⾔了。
同源策略限制以下⼏种⾏为:
1. Cookie、LocalStorage 和 IndexDB ⽆法读取
2. DOM 和 Js对象⽆法获得
3. AJAX 请求不能发送
模拟跨域问题
测试URL为
可以直接在浏览器console中执⾏
var xhr = new XMLHttpRequest();
xhr.open('GET', 'localhost:80/home/allProductions',true);
xhr.send();
adyState == 4) {
if(xhr.status == 200) {
console.log(JSON.sponseText));
}
}
}
在任意⽹站打开控制台,执⾏此段代码可以模拟跨域请求。
在知乎控制台打开报错如下
Mixed Content: The page at 'www.zhihu/question/26376773' was loaded over HTTPS, but r
equested an insecure XMLHttpRequest endpoint 'localhost/home/allProductions'. This request has been blocked; th
因为知乎是https,报错与普通的http协议不同。
再澄清⼀下跨域问题:
1. 并⾮浏览器限制了发起跨站请求,⽽是跨站请求可以正常发起,但是返回结果被浏览器拦截了。最好的例⼦是CRSF跨站攻击原理,⽆论是否跨域,请求已经发送到了后端服务器!
2. 但是,有些浏览器不允许从HTTPS的域跨域访问HTTP,⽐如Chrome和Firefox,这些浏览器在请求还未发出的时候就会拦截请求,这是⼀个特例。
在博客园控制台打开报错如下
XMLHttpRequest cannot load localhost/home/allProductions. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'wwwblogs' is therefore not allowed access.怎么解决跨域问题
解决⽅案有很多
1. 通过jsonp跨域
2. document.domain + iframe跨域
3. location.hash + iframe
4. window.name + iframe跨域
5. postMessage跨域
6. 跨域资源共享(CORS)
7.
8. nodejs中间件代理跨域
9. WebSocket协议跨域
这⾥主要介绍SpringMVC解决跨域问题的⽅式。
1. JSONP
2. CORS
3. WebSocket
JSONP
可以直接参考进⾏配置你的SpringMVC注解
JSONP 原理
我虽然请求不了json数据,但是我可以请求⼀个Content-Type为application/javascript的JavaScript对象,这样就可以避免浏览器的同源策略。
就是当服务器接受到名为jsonp或者callback的参数时,返回Content-Type: application/javascript的结果,从⽽避免浏览器的同源策略检测。
在控制台中直接进⾏测试你的jsonp是否配置成功:
function println(data) {
console.log(data);
}
var url = "localhost:80/home/allProductions?&callback=println";
// 创建script标签,设置其属性
var script = ateElement('script');
script.setAttribute('src', url);
// 把script标签加⼊head,此时调⽤开始
使⽤JQuery测试你的jsonp是否配置成功,因为控制台不能直接加载JQuery,需要⾃⼰建⽴html⽂件来进⾏测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="cdn.bootcss/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
function println(data) {
console.log(data);
console.log('print');
}
function jsonp_test() {
$.ajax({
type: "get",
url: "localhost:80/home/allProductions",
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页⾯的,⽤以获得jsonp回调函数名的参数名(⼀般默认为:callback)
jsonpCallback: "println", //返回后调⽤的处理函数
error: function () { //请求出错的处理
alert("请求出错");
}
});
}
</script>
</head>
<body onload="jsonp_test()">
</body>
</html>
CORS
CORS是⼀个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
iframe参数传递它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从⽽克服了AJAX只能同源使⽤的限制。
CORS需要浏览器和服务器同时⽀持。
1. 所有浏览器都⽀持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器⾃动完成,不需要⽤户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全⼀样。浏览器⼀旦发现AJAX请求跨源,就会⾃动添加⼀些附加的头信息,有时还会多出⼀次附加的请求,但⽤户不会有感觉。
2. 实现CORS通信的关键是服务器。只要服务器实现了CORS接⼝,就可以跨源通信。
即CORS与普通请求代码⼀样。
CORS与JSONP相⽐
1. JSONP只能实现GET请求,⽽CORS⽀持所有类型的HTTP请求。
2. 使⽤CORS,开发者可以使⽤普通的XMLHttpRequest发起请求和获得数据,⽐起JSONP有更好的错误处理。
3. JSONP主要被⽼的浏览器⽀持,它们往往不⽀持CORS,⽽绝⼤多数现代浏览器都已经⽀持了CORS。
@CrossOrigin注解
此注解既可⽤于⽅法也可⽤于类
源码如下:
@CrossOrigin(origins = "www.zhihu")
@RequestMapping(value = "/allProductions", method = RequestMethod.GET)
public Result getAllOldProductions() {
}
@CrossOrigin注解既可注解在⽅法上,也可注解在类上。
完成配置之后
XML全局配置
所有跨域请求都可以访问
<mvc:cors>
<mvc:mapping path="/**" />
</mvc:cors>
更加细粒度的配置:
<mvc:cors>
<mvc:mapping path="/api/**"
allowed-origins="domain1, domain2"
allowed-methods="GET, PUT"
allowed-headers="header1, header2, header3"
exposed-headers="header1, header2" allow-credentials="false"
max-age="123" />
<mvc:mapping path="/resources/**"
allowed-origins="domain1" />
</mvc:cors>
WebSocket
WebSocket是⼀种通信协议,使⽤ws://(⾮加密)和wss://(加密)作为协议前缀,在2008年诞⽣,2011年成为国际标准。所有浏览器都已经⽀持了。它的最⼤特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的⼀种。该协议不实⾏同源政策,只要服务器⽀持,就可以通过它进⾏跨源通信。
请求头信息:(多了个 origin)
GET /chat HTTP/1.1
Host: ample
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: example
响应头:(如果origin在⽩名单内)
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
相⽐于HTTP/2
HTTP/2只是对HTML、CSS等JS资源的传输⽅式进⾏了优化,并没有提供新的JS API,不能⽤于实时传输消息,也⽆法推送指定的信息。
参考⽂档:
1. 跨域
2. SpringMVC 跨域解决⽅法
3.

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。