Zuul统一异常处理
0
今天研究了一下Zuul,看书上的例子,最后发现异常处理的和书上的并不一样。
书上使用的是1.x
,我做的时候用的最新的2.x
的版本。这里也做一下记录。
首先是SendErrorFilter
这个类,现在filterType
已经是error
的了:
@Override
public String filterType() {
return ERROR_TYPE;
}
所以,现在异常都会到这个filter
里面,而这个filter
里面最后直接是forward
到了/error
这个链接上面。
所以这里就出现了一个很奇怪的现象,如果进入到Zuul的filter
链里面来后,在SendErrorFilter
之前发生了异常,那么我们会发现请求数据已返回后,会再次进入到我们自定义的post
的filter
里面。下面就是SendErrorFilter
里面的处理:
RequestDispatcher dispatcher = request.getRequestDispatcher(
this.errorPath);
if (dispatcher != null) {
ctx.set(SEND_ERROR_FILTER_RAN, true);
if (!ctx.getResponse().isCommitted()) {
ctx.setResponseStatusCode(exception.nStatusCode);
dispatcher.forward(request, ctx.getResponse());
}
}
所以现在我们不需要自定义error
的filter
,最后都会进入到/error
映射的方法里面。
然后我们看/error
,对应的文件是BasicErrorController
,里面有两个方法:errorHtml
和error
,看方法名就知道一个是返回html
一个是返回json
、xml
对象的。
他们是根据客户端请求是的accept
进行选择具体返回内容的。这里面返回的参数可以这样进行配置:
@Component
public class ErrorAttributeConfig extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
// Map<String, Object> result = super.getErrorAttributes(webRequest, includeStackTrace);
Map<String, Object> result = new HashMap<String, Object>();
result.put("code", 9999);
result.put("message", "系统错误");
result.put("sign", "系统签名");
return result;
}
}
当然如果你想自己重新/error
这个映射也是可以的,我们可以搜索一下BasicErrorController
在哪里定义的,可以看到:
@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
this.errorViewResolvers);
}
所以BasicErrorController
只有在我们没有定义自己的ErrorController
时才会生效,所以我们可以实现ErrorController
接口就可以定义/error
了:
@Controller
public class GlobalErrorController implements ErrorController {
@Override
public String getErrorPath() {
return "/error";
}
@ResponseBody
@RequestMapping("/error")
public String error() {
return "自定义错误信息";
}
}
这里再多说一下,上面的均是会进入到filter
的异常处理,如果是请求Zuul本身项目的一些异常需要使用@ControllerAdvice
来实现,这个和普通的Spring MVC项目就一样了:
@ControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(value = Exception.class)
// public ResponseEntity<Map<String, String>> defaultErrorHandler(HttpServletRequest request, Exception e)throws Exception {
public Map<String, String> defaultErrorHandler(HttpServletRequest request, Exception e)throws Exception {
Map<String, String> data = new HashMap<String, String>();
data.put("code", "9999");
data.put("message", "全局异常处理");
return data;
// return ResponseEntity.status(200).contentType(MediaType.APPLICATION_JSON_UTF8).body(data);
}
}
自定义404
和500
等页面:
@Configuration
public class ErrorPageConfig {
@Bean
public ErrorPageRegistrar errorPageRegistrar() {
return new ErrorPageRegistrar() {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
// registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/404.html"),
registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/404.html"),
new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500.html"));
}
};
}
}
DEMO地址:https://github.com/acgist/demo/tree/master/esc-eureka-gateway