11### 27.1.8 错误处理
22
3- Spring Boot默认提供一个/error映射用来以合适的方式处理所有的错误,并且它在servlet容器中注册了一个全局的
4- 错误页面。对于机器客户端(相对于浏览器而言,浏览器偏重于人的行为),它会产生一个具有详细错误,HTTP状态,异常信息的JSON响应。对于浏览器客户端,它会产生一个白色标签样式(whitelabel)的错误视图,该视图将以HTML格式显示同样的数据(可以添加一个解析为erro的View来自定义它 )。为了完全替换默认的行为,你可以实现ErrorController ,并注册一个该类型的bean定义,或简单地添加一个ErrorAttributes类型的bean以使用现存的机制 ,只是替换显示的内容。
3+ Spring Boot默认提供一个` /error ` 映射用来以合适的方式处理所有的错误,并且它注册为servlet容器中全局的
4+ 错误页面。对于机器客户端(相对于浏览器而言,浏览器偏重于人的行为),它会产生一个具有详细错误,HTTP状态,异常信息的JSON响应。对于浏览器客户端,它会产生一个白色标签样式(whitelabel)的错误视图,该视图将以HTML格式显示同样的数据(可以添加一个解析为'error'的View来自定义它 )。为了完全替换默认的行为,你可以实现 ` ErrorController ` ,并注册一个该类型的bean定义,或简单地添加一个 ` ErrorAttributes ` 类型的bean以使用现存的机制 ,只是替换显示的内容。
55
6- 如果在某些条件下需要比较多的错误页面,内嵌的servlet容器提供了一个统一的Java DSL(领域特定语言)来自定义错误处理。
7- 示例:
6+ ** 注** ` BasicErrorController ` 可以作为自定义` ErrorController ` 的基类,如果你想添加对新context type的处理(默认处理` text/html ` ),这会很有帮助。你只需要继承` BasicErrorController ` ,添加一个public方法,并注解带有` produces ` 属性的` @RequestMapping ` ,然后创建该新类型的bean。
7+
8+ 你也可以定义一个` @ControllerAdvice ` 去自定义某个特殊controller或exception类型的JSON文档:
9+ ``` java
10+ @ControllerAdvice (basePackageClasses = FooController . class)
11+ public class FooControllerAdvice extends ResponseEntityExceptionHandler {
12+
13+ @ExceptionHandler (YourException . class)
14+ @ResponseBody
15+ ResponseEntity<?> handleControllerException (HttpServletRequest request , Throwable ex ) {
16+ HttpStatus status = getStatus(request);
17+ return new ResponseEntity<> (new CustomErrorType (status. value(), ex. getMessage()), status);
18+ }
19+
20+ private HttpStatus getStatus (HttpServletRequest request ) {
21+ Integer statusCode = (Integer ) request. getAttribute(" javax.servlet.error.status_code" );
22+ if (statusCode == null ) {
23+ return HttpStatus . INTERNAL_SERVER_ERROR ;
24+ }
25+ return HttpStatus . valueOf(statusCode);
26+ }
27+
28+ }
29+ ```
30+ 在以上示例中,如果跟` FooController ` 相同package的某个controller抛出` YourException ` ,一个` CustomerErrorType ` 类型的POJO的json展示将代替` ErrorAttributes ` 展示。
31+
32+ ** 自定义错误页面**
33+
34+ 如果想为某个给定的状态码展示一个自定义的HTML错误页面,你需要将文件添加到` /error ` 文件夹下。错误页面既可以是静态HTML(比如,任何静态资源文件夹下添加的),也可以是使用模板构建的,文件名必须是明确的状态码或一系列标签。
35+
36+ 例如,映射` 404 ` 到一个静态HTML文件,你的目录结构可能如下:
37+ ``` properties
38+ src/
39+ +- main/
40+ +- java/
41+ | + <source code>
42+ +- resources/
43+ +- public/
44+ +- error/
45+ | +- 404.html
46+ +- <other public assets>
47+ ```
48+ 使用FreeMarker模板映射所有` 5xx ` 错误,你需要如下的目录结构:
49+ ``` properties
50+ src/
51+ +- main/
52+ +- java/
53+ | + <source code>
54+ +- resources/
55+ +- templates/
56+ +- error/
57+ | +- 5xx.ftl
58+ +- <other templates>
59+ ```
60+ 对于更复杂的映射,你可以添加实现` ErrorViewResolver ` 接口的beans:
61+ ``` java
62+ public class MyErrorViewResolver implements ErrorViewResolver {
63+
64+ @Override
65+ public ModelAndView resolveErrorView (HttpServletRequest request ,
66+ HttpStatus status , Map<String , Object > model ) {
67+ // Use the request or status to optionally return a ModelAndView
68+ return ...
69+ }
70+
71+ }
72+ ```
73+ 你也可以使用Spring MVC特性,比如[ @ExceptionHandler 方法] ( http://docs.spring.io/spring/docs/4.3.3.RELEASE/spring-framework-reference/htmlsingle/#mvc-exceptionhandlers ) 和[ @ControllerAdvice ] ( http://docs.spring.io/spring/docs/4.3.3.RELEASE/spring-framework-reference/htmlsingle/#mvc-ann-controller-advice ) ,` ErrorController ` 将处理所有未处理的异常。
74+
75+ ** 映射Spring MVC以外的错误页面**
76+
77+ 对于不使用Spring MVC的应用,你可以通过` ErrorPageRegistrar ` 接口直接注册` ErrorPages ` 。该抽象直接工作于底层内嵌servlet容器,即使你没有Spring MVC的` DispatcherServlet ` ,它们仍旧可以工作。
878``` java
979@Bean
10- public EmbeddedServletContainerCustomizer containerCustomizer (){
11- return new MyCustomizer ();
80+ public ErrorPageRegistrar errorPageRegistrar (){
81+ return new MyErrorPageRegistrar ();
1282}
1383
1484// ...
15- private static class MyCustomizer implements EmbeddedServletContainerCustomizer {
85+
86+ private static class MyErrorPageRegistrar implements ErrorPageRegistrar {
87+
1688 @Override
17- public void customize ( ConfigurableEmbeddedServletContainer container ) {
18- container . addErrorPages(new ErrorPage (HttpStatus . BAD_REQUEST , " /400" ));
89+ public void registerErrorPages ( ErrorPageRegistry registry ) {
90+ registry . addErrorPages(new ErrorPage (HttpStatus . BAD_REQUEST , " /400" ));
1991 }
92+
2093}
2194```
22- 你也可以使用常规的Spring MVC特性来处理错误,比如[ @ExceptionHandler 方法] ( http://docs.spring.io/spring/docs/4.1.4.RELEASE/spring-framework-reference/htmlsingle/#mvc-exceptionhandlers ) 和[ @ControllerAdvice ] ( http://docs.spring.io/spring/docs/4.1.4.RELEASE/spring-framework-reference/htmlsingle/#mvc-ann-controller-advice ) 。ErrorController将会捡起任何没有处理的异常。
23-
24- N.B. 如果你为一个路径注册一个ErrorPage,最终被一个过滤器(Filter)处理(对于一些非Spring web框架,像Jersey和Wicket这很常见),然后过滤器需要显式注册为一个ERROR分发器(dispatcher)。
95+ 注.如果你注册一个` ErrorPage ` ,该页面需要被一个` Filter ` 处理(在一些非Spring web框架中很常见,比如Jersey,Wicket),那么该` Filter ` 需要明确注册为一个` ERROR ` 分发器(dispatcher),例如:
2596``` java
2697@Bean
2798public FilterRegistrationBean myFilter() {
@@ -32,4 +103,8 @@ public FilterRegistrationBean myFilter() {
32103 return registration;
33104}
34105```
35- ** 注** :默认的FilterRegistrationBean没有包含ERROR分发器类型。
106+ (默认的` FilterRegistrationBean ` 不包含` ERROR ` dispatcher类型)。
107+
108+ ** WebSphere应用服务器的错误处理**
109+
110+ 当部署到一个servlet容器时,Spring Boot通过它的错误页面过滤器将带有错误状态的请求转发到恰当的错误页面。request只有在response还没提交时才能转发(forwarded)到正确的错误页面,而WebSphere应用服务器8.0及后续版本默认情况会在servlet方法成功执行后提交response,你需要设置` com.ibm.ws.webcontainer.invokeFlushAfterService ` 属性为` false ` 来关闭该行为。
0 commit comments