spring mvc 项目中,在使用 RestHandlerExceptionResolver 做统一异常处理的时候,有时候需要设置 handler 来解决跨域的问题。
公司现有的项目实现的逻辑是如果请求失败,通过 RestHandlerExceptionResolver 的 builder 方法 返回一个状态码为400 的错误信息给调用方。
@Bean
public RestHandlerExceptionResolver restExceptionResolver() {
return RestHandlerExceptionResolver.builder().messageSource(httpErrorMessageSource())
.defaultContentType(APPLICATION_JSON)
.addErrorMessageHandler(CrmException.class, BAD_REQUEST)
.build();
}
这样调用方在可以很方便的通过http 状态码来判断请求是否成功。 但是这样会有一个一个问题。 如果请求方和服务器不在一个域名下,返回异常的时候,会出现跨域的问题。原因是 RestHandlerExceptionResolver 没有做跨域处理。问题找到了,解决方案就是需要给 返回的数据中 设置响应头的 handler信息未可跨域。
方式是创建一个 异常类的handler继承 ErrorMessageRestExceptionHandler 。并重写createHeaders 方法。
public class CrmExceptionHandler extends ErrorMessageRestExceptionHandler<CrmException> {
public CrmExceptionHandler(Class exceptionClass, HttpStatus status) {
super(exceptionClass, status);
}
public CrmExceptionHandler(HttpStatus status) {
super(status);
}
public HttpHeaders createHeaders(CrmException ex, HttpServletRequest req) {
HttpHeaders headers = super.createHeaders(ex, req);
// 允许跨域访问
if (ObjectUtils.isEmpty(headers.getAccessControlAllowOrigin())) {
headers.setAccessControlAllowOrigin("*");
}
return headers;
}
}
调用 CrmExceptionHandler
@Bean
public RestHandlerExceptionResolver restExceptionResolver() {
return RestHandlerExceptionResolver.builder().messageSource(httpErrorMessageSource())
.defaultContentType(APPLICATION_JSON)
.addErrorMessageHandler(CrmException.class, BAD_REQUEST)
.addHandler(new CrmExceptionHandler(BAD_REQUEST)) // 设置异常信息响应头
.build();
}
以上解决了 系统返回异常信息的跨域问题
参考资料: https://github.com/jirutka/spring-rest-exception-handler