跨域请求的概念
浏览器出于安全的考虑,使用 XMLHttpRequest
对象发起 HTTP请求时必须遵守同源策略,否则就是跨域的HTTP请求,默认情况下是被禁止的。
同源策略要求源相同才能正常进行通信,即协议、域名【或者是主机名】、端口号都完全一致。
说通俗一点
- 浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域
- 只要协议、域名、端口有任何一个不同,都被当作是不同的域,之间的请求就是跨域操作。
例如:
前端 | 后端 |
---|---|
http://localost:8080 |
http://localhost:8081 |
协议相同,主机名相同,但端口号不同。这就是跨域请求。
注意
- 只有浏览器才会有这个跨域请求的问题,如果是移动端跨域请求就不会出现问题。
XMLHttpRequest
对象就是ajax
发送异步请求时使用的对象,所以也就是说浏览器使用ajax
请求时才会出现跨域请求的问题。总得来说,发生跨域请求问题的场景就是:浏览器使用
ajax
请求
解决方案
解决跨域请求有多种方案
我们可以使用CORS
解决跨域。
什么是CORS
CORS
是一个W3C
标准,全称是”跨域资源共享”(Cross-origin resource sharing),允许浏览器向跨源服务器,发出XMLHttpRequest
请求,从而克服了AJAX只能同源使用的限制。
它通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]
来告诉客户端跨域的限制,如果浏览器支持CORS
、并且判断Origin通过的话,就会允许XMLHttpRequest
发起跨域请求。
如果是一个跨域请求,就会再发送一个带有Origin
的请求头。里面的值就是这个页面所在的域
发送给服务器之后,如果我们配置了跨域,响应头就会带有Access-Control-Allow-Origin
,它的值表示服务器允许跨域的域,
如果该值和请求头的Origin
值一样,则表示允许跨域。就会请求成功。
如果我们要自己使用Cors
解决跨域请求的问题其实就是
解析请求头,然后去添加响应头就好了。但我们没必要自己去写,SpringBoot
有这样的解决跨域请求的拦截器,只需要配置就可以。
如果我们进行了
Cors
配置,但响应头中没有Access-Control-Allow-Origin
,说明我们的配置是有问题的。
SpringBoot使用CORS解决跨域
使用
@CrossOrigin
可以在支持跨域的方法上或者是Controller类上加上
@CrossOrigin
注解例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class UserController {
private UserServcie userServcie;
public ResponseResult findAll(){
//调用service查询数据 ,进行返回
List<User> users = userServcie.findAll();
return new ResponseResult(200,users);
}
}value
属性可以设置多个URL。origins
属性也可以设置多个URL。例如:@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
maxAge
属性指定了准备响应前的缓存持续的最大时间。就是探测请求的有效期。allowCredentials
属性表示用户是否可以发送、处理 cookie。默认为falseallowedHeaders
属性表示允许的请求头部有哪些。methods
属性表示允许请求的方法,默认get,post,head
如果你不设置他的value属性,或者是origins属性,就默认是可以允许所有的URL/域访问。
value和origins的效果是一样的,当value和origins同时使用时,配置的值不一样会报错!
使用
WebMvcConfigurer
的addCorsMappings
方法配置CorsInterceptor
使用注解有一个缺陷,当我们的Controller类过多时,就需要频繁加注解。因此我们可以使用配置类才进行批量映射。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class CorsConfig implements WebMvcConfigurer {
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路径
registry.addMapping("/**")
// 设置允许跨域请求的域名
.allowedOriginPatterns("*")
// 是否允许cookie
.allowCredentials(true)
// 设置允许的请求方式
.allowedMethods("GET", "POST", "DELETE", "PUT")
// 设置允许的header属性
.allowedHeaders("*")
// 跨域允许时间
.maxAge(3600);
}
}addMapping("/user/**")
:其中* 表示匹配到下一层;** 表示后面不管有多少层,都能匹配。allowedOriginPatterns("http:localhost:8080")
,只有http:localhost:8080
可以访问。*
表示任意域名.maxAge(3600);
:如果我们使用比较复杂的请求,比如
PUT
请求。那这个请求它不是只发送一个请求,如果是跨域请求,浏览器会先发送一个询问允许我跨域请求的请求。如果服务端是允许的,就会再响应头中添加对应的响应头。
如果每次请求都发送一个询问请求那就会很浪费时间。
而
maxAge
相当于持久的时间。如果我们这个请求被允许了,那在3600秒之内,浏览器再去发送跨域请求,就不会再发送询问请求。
当时使用SpringSecurity时
当有跨域请求时,还得经过SringSecurity
的过滤器,光靠SpringBoot
是不行的,如果SpringSecurity
是不允许跨域的还是不行。
因此还需要配置SpringSecurity
来进行跨域请求。配置方法如下:http.cors();
1 |
|
__END__