跨域问题
浏览器同源策略
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。
同源策略,它是由Netscape提出的一个著名的安全策略。
现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。
如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
产生跨域的原因
同时满足:
- 浏览器限制
- 跨域
- XHR(XMLHttpRequest)请求
解决思路
一、 浏览器
以Chrome浏览器为例
找到chrome.exe所在目录,并在当前目录打开cmd
用cmd带参数启动一个Chrome:
命令: chrome --disable-web-security --user-data-dir=g:temp3
要带上--user-data-dir=g:temp3 否则不起作用
新打开的浏览器提示下面信息时,说明已经成功,浏览器不会做同源校验
二、 XHR
1. 使用JSONP
- JSONP是什么
JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。
由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外。
利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。
用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
- 使用JSONP后台需要改动吗
// 前端请求测试代码
$.ajax({
url: '//localhost:8080/test/get',
type: 'get',
/*dataType: 'jsonp',*/
success: function(data){
console.log(JSON.stringify(data))
}
})
未添加dataType: 'jsonp':
浏览器报:No 'Access-Control-Allow-Origin' , 未报其他错误
添加上 dataType: 'jsonp'
浏览器报jQuery错误
原因:
-
Spring boot 框架下支持JSONP
使用AbstractJsonpResponseBodyAdvice来支持跨域请求很简单,只需要继承这个类就可以了。具体代码如下:
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpAdvice() {
super("callback");
}
}
添加上已上代码后,再次请求接口,浏览器没有报错,取得正确结果:
/**/jQuery32107660470166019324_1524727420424({"悟空":"是只猴子"});
请求url:
http://localhost:8080/test/get?callback=jQuery32107660470166019324_1524727420424&_=1524727420425
callback=jQuery32107660470166019324_1524727420424
callback参数是jQuery处理生成的
JSONP请求成功的原因 ?
非jsonp请求:
jsonp请求:
jsonp发送的请求是script请求,区别于xhr请求,不存在跨域的问题。
原理:jsonp请求中,对应后台中约定的callback,json代码的内容就是callback的值作为函数名,返回的的数据作为函数的参数。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
xhr请求与JSONP请求区别:
1. 请求type不同, json请求为xhr,jsonp为script
2. 返回类型不同,jsonp返回的是javascript, 普通的xhr请求返回的是json数据对象
3. 请求URL的不同,请求带有callback字段
JSONP请求参数
callback:jQuery32107660470166019324_1524727420424
_:1524727420425
参数'_'的作用是: 防止该请求被缓存
在ajax请求中加入 cache: true ( 表示该请求可以被缓存 )时,再次请求,则参数中没有' _ ' 参数
JSONP的弊端
● 服务端需要改动
● 只支持GET请求
● 发送的不是XHR请求
JSONP请求时 无法使用beforeSend,complete等回调函数
ajax请求时指定dataType为jsonp类型,意味着将会通过script标签而不是XMLHttpRequest对象从从服务器接收数据。这种情况下,
$.ajax()不再返回XMLHttpRequest对象,并且也不会传递事件处理函数,比如beforeSend。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
2. 被调用方解决
待补充
****带cookie的跨域****
默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等)。
通过将withCredentials属性设置为true,可以指定某个请求应该发送凭据。
$.ajax({
url: a_cross_domain_url,
xhrFields: {
withCredentials: true
}
})
如果服务器接收带凭据的请求,会用下面的HTTP头部来响应。Access-Control-Allow-Credentials: true
在Java
下的实现大概是这个样子:
response.addHeader("Access-Control-Allow-Credentials", "true");
带cookie跨域的Access-Control-Allow-Origin
头,再设置为*
就不行了,会报错。
在Access-Control-Allow-Credentials
设置为true
的时候,Access-Control-Allow-Origin
不能被设置为通配符。所以解决思路就是在返回的时候设置为请求头中Origin
的值。
在Java下的实现大致是这样的:
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
这样就能实现基于cors的携带cookies的跨域访问了。
另外,支持withCredentials属性的浏览器有Firefox 3.5+、Safari 4+和Chrome。IE10及更早版本都不支持。
3. 调用方解决
待补充
---------------------------------
跨域相关文章:
上一篇: 无光驱无U盘 硬盘安装Win7系统教程
下一篇: Tomcat服务器配置