SpringBoot的后端拦截器以及跨域问题:
在前后端分离的请跨下,前端的设置的跨域是基于node服务的,在项目发布的时候,只是当个的文件,是没有node服务的,所以后端跨域就显得尤为重要:
前端跨域(基于node服务):
proxyTable: {
'/api': {
target: 'http://localhost:8080/', // 设置你调用的接口域名和端口号
changeOrigin: true, // 跨域
pathRewrite: {
'^/api': '/'
}
}
},
而在后端设置跨域后,又因为加的有拦截器,所以前端发过来的token就会被拦截器直接过滤掉,所以我们需要对CorsFilter进行一些配置(在使用shiro的时候,似乎不太好用):
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加拦截器
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/user/**");
}
//配置跨域
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8081")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT")
.maxAge(3600);
}
private CorsConfiguration addCorsConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
List<String> list = new ArrayList<>();
list.add("*");
corsConfiguration.setAllowedOrigins(list);
/*
// 请求常用的三种配置,*代表允许所有,当时你也可以自定义属性(比如header只能带什么,只能是post方式等等)
*/
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", this.addCorsConfig());
return new CorsFilter(source);
}
}
拦截器:
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
BaseResult baseResult = new BaseResult();
String token = request.getHeader("token");
response.setContentType("application/json;charset=utf-8");
try {
if (StringUtil.isEmpty(token)){
PrintWriter writer = response.getWriter();
baseResult.setCode(0);
baseResult.setMessage("用户未登录");
writer.write(JSON.toJSONString(baseResult));
return false;
}
JwtUtils jwtUtils = new JwtUtils();
String s = jwtUtils.VerifyToekn(token);
System.out.println(s);
return true;
}catch (Exception e){
System.out.println(e.getMessage());
PrintWriter writer = response.getWriter();
baseResult.setCode(0);
baseResult.setMessage("用户token验证失败");
writer.write(JSON.toJSONString(baseResult));
return false;
}
}
}
其根本原因:
实际上发送了两次请求,第一次为OPTIONS请求,第二次才GET/POST等请求
在OPTIONS请求中,不会携带请求头的参数,所以在拦截器上获取请求头为空,自定义的拦截器拦截成功
第一次请求不能通过,就不能获取第二次的请求了GET/POST…
第一次请求不带参数,第二次请求才带参数
另外一种解决方法:
在拦截器中,如果请求为OPTIONS请求,则返回true,表示可以正常访问,然后就会收到真正的GET/POST请求
拦截器
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//如果是OPTIONS请求的话 进行直接放行
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())){
System.out.println("OPTIONS请求放行");
return true;
}
BaseResult baseResult = new BaseResult();
String token = request.getHeader("token");
response.setContentType("application/json;charset=utf-8");
try {
if (StringUtil.isEmpty(token)){
PrintWriter writer = response.getWriter();
baseResult.setCode(0);
baseResult.setMessage("用户未登录");
writer.write(JSON.toJSONString(baseResult));
return false;
}
JwtUtils jwtUtils = new JwtUtils();
String s = jwtUtils.VerifyToekn(token);
System.out.println(s);
return true;
}catch (Exception e){
System.out.println(e.getMessage());
PrintWriter writer = response.getWriter();
baseResult.setCode(0);
baseResult.setMessage("用户token验证失败");
writer.write(JSON.toJSONString(baseResult));
return false;
}
}
}
配置类:
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加拦截器
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/user/**");
}
@Override
//配置跨域
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedHeaders("*")
.allowedMethods("*")
//.allowedMethods("GET", "POST", "DELETE", "PUT")
.allowedOrigins("http://localhost:8081","http://localhost:9000")
//.allowedOriginPatterns("http://localhost:8081","http://localhost:9000")
.allowCredentials(true);
}
}