Spring MVC CORS not working for error controllers

2019-09-12 13:31发布

问题:

I have my Spring MVC application configured to use CORS as such:

@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**");
}

This works fine for successful requests however when an exception is thrown and is picked up by my error handler, CORS headers are not added.

@ControllerAdvice
public class ApiErrorHandler {

   @ExceptionHandler(value = HttpClientErrorException.class)
   public ResponseEntity badRequest(Exception ex) 
   {
       return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorBodyWrapper.wrapErrorInJson(ex.getMessage()));
   }
}

Is there a reason CORS does not work for error handlers?

Thanks

回答1:

same with you.

@Configuration
public class ManagerWarInit extends WebMvcConfigurerAdapter {

    ... 

    private static final String[] SUPPORT_METHODS = new String[] {
            HttpMethod.HEAD.name(),
            HttpMethod.OPTIONS.name(),

            HttpMethod.GET.name(),
            HttpMethod.POST.name(),

            HttpMethod.PUT.name(),
            HttpMethod.DELETE.name()
    };
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedMethods(SUPPORT_METHODS)
                .exposedHeaders("Set-Cookie");
    }
}

and globalException

@ControllerAdvice
public class ManagerGlobalException {

    // @CrossOrigin(...)
    @ExceptionHandler(NotLoginException.class)
    public void noLogin(NotLoginException e, HttpServletResponse response)
                       throws IOException {
        if (LOG.isDebugEnabled())
            LOG.debug(e.getMessage());

        if (RequestUtils.isAjaxRequest()) {
            RequestUtils.toJson(notLogin(), response);
        } else {
            response.sendRedirect("hxxp://www.xxx.com");
        }
    }
}

but Cross-domain calls error by Browser(Chrome etc.)

XMLHttpRequest cannot load hxxp://127.0.0.1:8080/url... No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'hxxp://127.0.0.1:3000' is therefore not allowed access.

Trying to add a @CrossOrigin annotation on ExceptionHandler still has this error

I am dealing with this now

@ControllerAdvice
public class ManagerGlobalException {

    @ExceptionHandler(NotLoginException.class)
    public String notLogin(NotLoginException e) throws IOException {
        if (LOG.isDebugEnabled())
            LOG.debug(e.getMessage());

        if (RequestUtils.isAjaxRequest()) {
            return "forward:/not-login";
        } else {
            return "redirect:hxxp://www.xxx.com";
        }
    }
}

add a mapping

@RestController
public class IndexController {

    @RequestMapping(value = "/not-login")
    public JsonResult notLogin() {
        return JsonResult.notLogin();
    }
}


回答2:

I think by default the only method added to the mapping is GET, In your "addCorsMappings" try to specify the methods you want to add the header to

       registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD");


回答3:

Using Spring CorsFilter can resolve this problem.

    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);

        config.addAllowedOrigin("*");

        config.addAllowedHeader("*");
        config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));

        bean.setOrder(0);
        return bean;
    }