1.JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象(JavaScript同源策略的限制)
2.当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域
3.不同域之间相互请求资源,就算作“跨域”
(1)跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了
(2)受到了同源策略的限制,同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。
(3)如果是协议和端口造成的跨域问题“前台”是无能为力的
(4)在跨域问题上,域仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断
(5)“URL的首部”可以理解为“协议, 域名和端口必须匹配”
4.同源策略及其限制
(1)同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互
(2)这是一个用于隔离潜在恶意文件的关键的安全机制
(3)它的存在可以保护用户隐私信息,防止身份伪造等(读取Cookie)
(4)同源策略限制内容有:
<1>Cookie、LocalStorage、IndexedDB 等存储性内容
<2>DOM 节点
<3>AJAX 请求不能发送
(5)但是有三个标签是允许跨域加载资源:
<1><img src=XXX>
<2><link href=XXX>
<3><script src=XXX>
5.所有的跨域都必须经过信息提供方的允许。如果未经允许即可获取,那是浏览器同源策略出现漏洞。
6.处理跨域方法
(1)处理跨域方法一——JSONP
<1>JSONP原理:
1.利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 数据
2.JSONP请求一定需要对方的服务器做支持才可以
<3>JSONP和AJAX对比:
1.AJAX属于同源策略,JSONP属于非同源策略(跨域请求)
2.都是客户端向服务器端发送请求,从服务器端获取数据的方式
<4>JSONP优缺点
1.JSONP优点是兼容性好,可用于解决主流浏览器的跨域数据访问的问题
2.缺点是仅支持get方法具有局限性。
<5>JSONP的流程
常规形式:
<script type="text/javascript">
function fn(data) { alert(data.msg); }
</script>
<script type="text/javascript" src="http://crossdomain.com/jsonServerResponse?jsonp=fn"></script>
1.其中 fn 是客户端注册的回调的函数,目的获取跨域服务器上的json数据后,对数据进行在处理
2.服务器返回给客户端数据的格式为:fn({ msg:'this is json data'})
jQuery形式:
$.ajax({ url:"http://crossdomain.com/jsonServerResponse",
dataType:"jsonp",
//可以省略
type:"get",
//自定义传递给服务器的函数名,而不是使用jQuery自动生成的,可省略
jsonpCallback:"fn",
//把传递函数名的那个形参callback变为jsonp,可省略
jsonp:"jsonp",
success:function (data){ console.log(data);} });
1.JSONP都是GET和异步请求的,不存在其他的请求方式和同步请求
2.jQuery默认就会给JSONP的请求清除缓存
(2)处理跨域方法二——CORS(重点)
<1>CORS原理
1.整个CORS通信过程,都是浏览器自动完成,不需要用户参与
2.CORS通信与同源的AJAX通信没有差别,代码完全一样
3.浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,用户不会有感觉
4.实现CORS通信的关键是服务器,目前主流的浏览器都实现了CORS
5.只要服务器实现了CORS接口,就可以跨源通信
<2>CORS优缺点
1.CORS要求浏览器(>IE10)和服务器的同时支持
2.跨域的根本解决方法,由浏览器自动完成。
3.优点在于功能更加强大支持各种HTTP Method,缺点是兼容性不如JSONP
4.只需要在服务器端做一些小小的改造即可:
header("Access-Control-Allow-Origin:*");
header("Access-Control-Allow-Methods:POST,GET");
(3)处理跨域方法三——WebMvcConfigurer
<1>属于全局配置,CORS属于局部配置
<2>设置跨域规则,从使用上也非常的简单
@Configuration
public class CrossOriginConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 允许的请求路径
registry.addMapping(""/test/cors"")
// 允许的请求方式
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
// 允许的请求源
.allowedOrigins("*")
// 允许的请求头
.allowedHeaders("*")
// 配置客户端缓存预检请求的响应的时间(以秒为单位)。默认设置为1800秒(30分钟)。
.maxAge(3600)
// 浏览器是否应该发送凭据
.allowCredentials(true);
}
}
<3>等价的xml的方式表达:
<mvc:cors>
<mvc:mapping path="/test/cors" ... />
</mvc:cors>
(4)还有其余的跨域处理方式(WebSocket、postMessage),这里不做解释
7.处理跨域方法二——CORS后端处理方式
方式一:Spring MVC 4.2之前的做法
(1)第一种:
<1>简单的自定义CORSFilter / Interceptor implements Filter
// 自定义一个Filter来处理CORS跨域请求
@Component
public class CORSFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "content-type,Authorization");
// response.setHeader("Access-Control-Allow-Credentials", "true");
filterChain.doFilter(servletRequest, servletResponse);}
@Override
public void destroy() {}}
<2>在web.xml 中添加filter
<filter>
<filter-name>corsFilter</filter-name>
<filter-class>com.filter.CorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
(2)第二种:
<1>添加两个依赖:
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>java-property-utils</artifactId>
<version>1.9.1</version>
</dependency>
<2>在web.xml中配置:
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<init-param>
<param-name>cors.allowGenericHttpRequests</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.allowSubdomains</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>GET, POST, HEAD, PUT, DELETE</param-value>
</init-param>
<init-param>
<param-name>cors.supportedHeaders</param-name>
<param-value>*</param-value>
</init-param>
</filter>
<3>web.xml里dispatchOptionsRequest true 允许校验请求
方式二:在Spring MVC4.2之后推出了@CrossOrigin注解来解决跨域问题
(6)如果觉得使用CorsFilter配置起来麻烦,@CrossOrigin想实现精细化且更加简便的控制
(7)@CrossOrigin关注方法,它使用方式极其简单,如下案例:
@CrossOrigin(origins = "*", methods = {GET, POST, PUT, DELETE}, maxAge = 60L)
@RequestMapping(value = "/test/cors", method = {OPTIONS, GET})
public Object TestCorsContorller() {
return "hello cors";
}
<1>origins:允许可访问的域列表;*表示可以是任何来源
<2>maxAge:准备响应前的缓存持续的最大时间(单位:秒)
(8)注解失效问题:@RequestMapping注解中需要声明请求方式即增加method=RequestMethod.XXX
(9)添加注解后session失效问题:ajax请求中需要添加xhrFields:{withCredentials:true}(每个ajax中都需要加此属性,以保证session一致)
(10)注意:
<1>方法一对的是URL,允许整个项目跨域访问,可通过filter来进行过虑;
<2>方法三针对Contorller方法,@CrossOrigin
@CrossOrigin中的2个参数:
origins:允许可访问的域列表
maxAge:准备响应前的缓存持续的最大时间(以秒为单位)