记录一次自己搭建项目时,使用Filter实现统一响应体时遇到的跨域问题。
问题:定义了两个Filter过滤器,设置 corsFilter优先执行,ResponseFilter在执行后将返回体重新设置。导致跨域失败
@Configuration
public class ApplicationAutoConfig {
@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:8080");
config.setAllowCredentials(true);
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.addExposedHeader("*");
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean(new CorsFilter(corsConfigurationSource));
bean.setOrder(0);
bean.addUrlPatterns("/*");
return bean;
}
@Bean
public FilterRegistrationBean<ResponseFilter> responseFilter() {
FilterRegistrationBean<ResponseFilter> bean = new FilterRegistrationBean(new ResponseFilter());
bean.setOrder(Integer.MAX_VALUE);
return bean;
}
}
由于在ReponseFilter中将request和reponse请求进行了封装,wrapResponse()方法中,将缓存中数据取出来后,会执行重置缓存区,原来调用的是 reset() 方法,reset方法会调用父类的reset方法去把reponse中的数据也清除掉包括设置的跨域头信息等,所以我们只需要清除掉缓存区中;将 reset()方法换成 resetBuffer() 即可
@Override
public void reset() {
super.reset();
this.content.reset();
}
public void reset() {
this.response.reset();
}
public class ResponseFilter extends OncePerRequestFilter {
private static final Set<String> ALLOWED_PATH = Collections.unmodifiableSet(
new HashSet<>(Arrays.asList(
"/swagger-ui.html",
"/v2/api-doc",
"/swagger-resources",
"/webjars")));
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
filterChain.doFilter(requestWrapper, responseWrapper);
wrapResponse(responseWrapper);
responseWrapper.copyBodyToResponse();
}
private void wrapResponse(ContentCachingResponseWrapper response) throws IOException {
byte[] b = response.getContentAsByteArray();
if (b.length > 0) {
response.resetBuffer();
}
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(JSON.toJSONBytes(ResponseData.ok(JSON.parse(b))));
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String path = request.getRequestURI().substring(request.getContextPath().length()).replaceAll("[/]+$", "");
return ALLOWED_PATH.stream().anyMatch(path::startsWith) || StringUtils.isBlank(path);
}
}