跨域
跨域(Cross-Origin)
是指在Web开发中,当一个网页的脚本试图访问来自不同源(即协议、域名或端口号任意一个不同)的资源时,就会发生跨域问题。这是出于安全考虑,浏览器限制了跨域访问,防止恶意脚本窃取用户信息或对其他网站造成攻击。
常见的跨域
- AJAX请求跨域:当一个网页通过AJAX请求访问另一个域名下的资源时,由于浏览器的同源策略,会产生跨域问题。
- 嵌入第三方资源:当一个网页嵌入来自其他域名的图片、视频、广告等资源时,如果该资源所在的域名与当前页面的域名不同,也会发生跨域问题。
- 跨窗口通信:当网页中的两个窗口(如iframe)分别来自不同的域名,且它们需要进行数据交互时,也会遇到跨域问题。
- 域名跳转:当一个网站将用户从一个域名重定向到另一个域名时,也会涉及跨域问题。
- CDN加速:当网站使用CDN服务加速静态资源时,由于CDN服务器可能位于不同的域名下,访问静态资源也可能出现跨域问题。
springboot中常见的跨域解决方案
1.使用 @CrossOrigin 注解:可以在Controller层方法上使用该注解,允许特定来源的请求跨域访问。
// 允许所有来源的GET和POST请求访问该Controller:
@RestController
@CrossOrigin
public class MyController {
@GetMapping("/hello")
public String hello() {
return "Hello World!";
}
@PostMapping("/save")
public void save(@RequestBody User user) {
// 保存用户信息
}
}
// 允许特定来源的所有请求访问该Controller,并允许携带凭证信息:
@RestController
@CrossOrigin
public class MyController {
@GetMapping("/hello")
public String hello() {
return "Hello World!";
}
@PostMapping("/save")
public void save(@RequestBody User user) {
// 保存用户信息
}
}
2.配置WebMvcConfigurer:通过实现WebMvcConfigurer接口,在其addCorsMappings方法中配置跨域规则。
/**
* 方法一:
allowCredentials(true) 时,allowedOrigins("*") 是互相矛盾的此时只能具体到对应域名
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
@Bean
public CorsFilter corsFilter() {
return new CorsFilter(httpServletRequest -> {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(false);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setMaxAge(3600L);
return config;
});
}
3.使用Filter过滤器:创建一个Filter来拦截请求,在响应头中添加Access-Control-Allow-Origin等相关的响应头信息。
/**
* Access-Control-Allow-Origin 设置为 * 表示允许所有来源进行跨域请求。
* Access-Control-Allow-Credentials 设置为 true 表示允许携带凭证信息进行跨域请求。
* Access-Control-Allow-Methods 设置为 GET, POST, PUT, DELETE, OPTIONS 表示允许的HTTP方法。
* Access-Control-Max-Age 设置为 3600 表示预检请求(OPTIONS请求)的缓存时间。
* Access-Control-Allow-Headers 设置为一组允许的请求头字段。
*/
@Component
public class MyCorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, X-Requested-With, remember-me,token");
if (request.getMethod().equals("OPTIONS")) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
}
// 配置完过滤器后,需要将过滤器注册到 springboot 当中
@Bean
public FilterRegistrationBean<MyCorsFilter> corsFilterRegistry() {
FilterRegistrationBean<MyCorsFilter> bean = new FilterRegistrationBean<>(new MyCorsFilter());
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
4.使用Spring Security:如果项目中使用了Spring Security,可以通过配置HttpSecurity来实现跨域访问控制。
@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
// 其他HttpSecurity配置
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.and().formLogin();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList("Content-Type", "Authorization"));
configuration.setExposedHeaders(Arrays.asList("Authorization", "X-Total-Count"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
VUE调试阶段
const instance = axios.create({
baseURL: process.env.VUE_APP_BASEURL,
withCredentials: false
})
Nginx 跨域解决
可以在Nginx的配置文件中添加以下代码来设置响应头信息:
location /api {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
}