同源策略与跨域请求
一 同源策略与跨域请求
首先,跨域不是问题。是一种安全机制
1. 同源策略介绍
跨域是浏览器加载了与当前域名、协议、端口不同另一站点下的资源,这与各大支持JavaScript的浏览器的同源策略是违背的。
所谓同源策略,它是由Netscape提出的一个著名的安全策略。是防止外网的脚本恶意攻击服务器的一种措施。
现在所有支持JavaScript 的浏览器都会使用这个策略。
所谓同源是指,域名,协议,端口相同。
2. 跨域请求的问题
-- 前后端分离的开发环境下
跨域并不会阻止请求的发出,也不会阻止请求的接受,跨域是浏览器为了保护当前页面,你的请求得到了响应,浏览器不会把响应的数据交给页面上的回调,取而代之的是去提示你这是一个跨域数据。提示就是一个报错提醒
知道了浏览器是如何处理的了,才能对症下药来解决这个问题,下面介绍几种常用的跨域解决方法
二 解决跨域请求的问题
1. 跨域资源共享CORS
这是最靠谱也是非常科学的解决方案,通过Access-Control-Allow-Origin
响应头,告诉浏览器如果请求我的资源的页面
是 我这个响应头里记录了的"源"
,则不要拦截此响应,允许数据通行。
header头字段 | 含义 | 取值 |
---|---|---|
Access-Control-Allow-Credentials | 响应头表示是否可以将对请求的响应暴露给页面。返回true则可以,其他值均不可以。 | true/false |
Access-Control-Allow-Headers | 表示此次请求中可以使用那些header字段 | 符合请求头规范的字符串 |
Access-Control-Allow-Methods | 表示此次请求中可以使用那些请求方法 | GET/POST(多个使用逗号隔开) |
2. 跨域请求与Cookie
3. 前端解决方案JSONP
当服务端没有返回Access-Control-Allow-Origin
这样的字段时,是否就意味着不能使用此资源了吗?不!只能说不建议使用此资源了。但我们还有另一种办法,那就是通过JSONP。
三 SpringBoot跨域配置
java解决CORS跨域请求的方式,主要有以下几种方式可供选择:
- 返回新的CorsFilter
- 重写 WebMvcConfigurer
- 使用注解 @CrossOrigin
- 自定义web filter 实现跨域 (手动设置响应头 :HttpServletResponse)
1. CorsFilter★★★
返回新的CorsFilter(全局跨域)
在任意配置类,返回一个 新的 CorsFIlter Bean ,并添加映射路径和具体的CORS配置路径。
/**
*
* 设置跨域请求
**/
@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 4 对接口配置跨域设置 “*”代表全部。”**”代表适配所有接口。
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
}
2. WebMvcConfigurer
重写WebMvcConfigurer(全局跨域)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//是否发送Cookie
.allowCredentials(true)
//放行哪些原始域
.allowedOrigins("*")
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
.allowedHeaders("*")
.exposedHeaders("*");
}
}
3. @CrossOrgin
可以用在方法上,也可以用在类上。如果你不设置他的value属性,或者是origins属性,就默认是可以允许所有的URL/域访问
//@CrossOrigin 表示所有的URL均可访问此资源
@CrossOrigin(origins = "http://127.0.0.1:8093")//表示只允许这一个url可以跨域访问这个controller
@RestController
@RequestMapping("/testCorss")
public class CorssOriginController {
//可以对方法运用该注解
//@CrossOrigin(origins = "http://127.0.0.1:8093")
@GetMapping("/getString")
public String getString(){
return "跨域成功!";
}
}
- value 属性可以设置多个URL。
- origins 属性也可以设置多个URL。
- maxAge 属性指定了准备响应前的缓存持续的最大时间。就是探测请求的有效期。
- allowCredentials 属性表示用户是否可以发送、处理 cookie。默认为false
- allowedHeaders 属性表示允许的请求头部有哪些。
- methods 属性表示允许请求的方法,默认get,post,head。
4. 通过filter实现跨域
使用自定义filter,手动设置响应头实现跨域,定义一个类、实现Filter接口即可
@Component
public class MyCorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
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", "x-requested-with,content-type");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
也可以通过手动设置响应头实现局部跨域:
再具体的方法中使用 HttpServletResponse 对象添加响应头(Access-Control-Allow-Origin)来授权放行即可
@RequestMapping("/index")
public String index(HttpServletResponse response) {
response.addHeader("Access-Allow-Control-Origin","*");
return "index";
}