前后端跨域问题由浏览器同源策略而来,出现了跨域问题,实际上,请求是可以到达后端控制器内部的,浏览器会因为同源策略将后端返回的结果屏蔽,并向外说明跨域错误。
解决跨域问题的一些方法(不全,后面遇上不同的解决方法再补上,此文持续更新)
1、后端接口或路由方法上添加@CrossOrigin注解
放后端接口上:
放单个路由方法上:
2、在路由方法里的响应体中配置响应头:
ps: 想要哪个控制器里的方法跨域,只需将下面代码复制粘贴到该方法里就行
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
response.addHeader("Access-Control-Allow-Origin","*");
该方法体现了方法1中 @CrossOrigin 注解能实现跨域的本质( @CrossOrigin 注解在内部也是给响应头配置了上面那个参数,但是配置会更详尽一些)
3、写个配置类实现WebMvcConfigurer类,再重写addCorsMappings方法
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
直接写个配置类实现WebMvcConfigurer类,将上面重写的方法复制粘贴进去就行。附上包名全路径,防导错包。
4、通过给spring注入一个CorsFilter (跨域过滤器)的方法实现
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class AA {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
// 设置访问源地址
config.addAllowedOriginPattern("*");
// 设置访问源请求头
config.addAllowedHeader("*");
// 设置访问源请求方法
config.addAllowedMethod("*");
// 有效期 1800秒
config.setMaxAge(1800L);
// 添加映射路径,拦截一切请求
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
// 返回新的CorsFilter
return new CorsFilter(source);
}
}
直接写个配置类,然后将AA类里的代码直接原封不动复制粘贴进去就行,更多的配置可以自定义。注意上面特意把导入的包名全路径给了出来,因为容易选错了包,则实现不了效果。
5、引言:前面第1、2种方法肯定不是推荐使用的,因为一个项目中的路由方法很多,1、2种方法需要逐个添加,但是可以把第2种方法改良一下。
思路:写一个拦截器,在拦截器里添加方法2中的代码。
注:“拦截器” 通俗理解,起到了一个钩子的作用,好比后端spring的前置通知、前端vue中vue实例的生命周期中谈的几个钩子函数,没前端浏览器发送的所有请求,在进入控制器里的具体代码之前(包括进入路由映射之前),都会先进入这个叫做 “拦截器” 的东西,我们就是要在 “拦截器” 里用方法2,这样免去了每个路由方法手动配置跨域参数的弊端。
您瞧:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 增加一个拦截器,可以对拦截请求做一些自定义处理
registry.addInterceptor(new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//添加这么一条代码
response.addHeader("Access-Control-Allow-Origin","*");
System.out.println("拦截请求");
return true;
}
})
// 设置拦截器的过滤路径规则:/** 代码所有请求都拦下来去执行(重写的preHandle方法里的内容)
.addPathPatterns("/**")
// 设置不需要拦截的过滤规则:不拦截/admin/login请求
.excludePathPatterns("/admin/login");
}
}
这里还有前端配置跨域代理和后端的nginx(反向代理),微服务(配置网关)的方法来解决跨域问题,这里呼应文首的 “文章持续跟新”,遇上了再详细记录。