溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringBoot怎么定制錯誤頁面及錯誤數據

發布時間:2021-12-02 14:13:44 來源:億速云 閱讀:126 作者:iii 欄目:開發技術
# SpringBoot怎么定制錯誤頁面及錯誤數據

## 前言

在Web應用開發中,錯誤處理是用戶體驗的重要組成部分。SpringBoot提供了強大的錯誤處理機制,允許開發者靈活定制錯誤頁面和錯誤數據。本文將深入探討SpringBoot錯誤處理的原理、實現方式以及高級定制技巧。

## 一、SpringBoot錯誤處理機制概述

### 1.1 默認錯誤處理

SpringBoot默認通過`BasicErrorController`處理錯誤請求:

```java
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
    // 處理HTML錯誤響應
    @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        // ...
    }
    
    // 處理JSON錯誤響應
    @RequestMapping
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        // ...
    }
}

1.2 錯誤屬性解析

SpringBoot通過ErrorAttributes接口收集錯誤信息:

public interface ErrorAttributes {
    Map<String, Object> getErrorAttributes(WebRequest webRequest, 
        ErrorAttributeOptions options);
    Throwable getError(WebRequest webRequest);
}

默認實現DefaultErrorAttributes提供了以下信息: - timestamp:時間戳 - status:HTTP狀態碼 - error:錯誤原因 - message:錯誤消息 - path:請求路徑

二、定制錯誤頁面

2.1 靜態錯誤頁面

最簡單的定制方式是在src/main/resources/static/error/目錄下添加靜態HTML:

resources/
└── static/
    └── error/
        ├── 404.html
        ├── 500.html
        └── 5xx.html

命名規則: - 精確匹配:404.html - 范圍匹配:5xx.html - 通用匹配:error.html

2.2 動態模板錯誤頁面

對于動態內容,可以使用模板引擎(Thymeleaf、Freemarker等):

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Error Page</title>
</head>
<body>
    <h1 th:text="${status}">Status</h1>
    <p th:text="${error}">Error</p>
    <p th:text="${message}">Message</p>
    <p th:text="${path}">Path</p>
</body>
</html>

存放位置:

resources/
└── templates/
    └── error/
        ├── 404.html
        └── 500.html

2.3 自定義ErrorController

完全控制錯誤處理邏輯:

@Controller
public class MyErrorController implements ErrorController {

    @RequestMapping("/error")
    public String handleError(HttpServletRequest request) {
        Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
        
        if (status != null) {
            int statusCode = Integer.parseInt(status.toString());
            
            if(statusCode == HttpStatus.NOT_FOUND.value()) {
                return "error-404";
            } else if(statusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
                return "error-500";
            }
        }
        return "error";
    }
}

三、定制錯誤數據

3.1 實現ErrorAttributes接口

@Component
public class CustomErrorAttributes extends DefaultErrorAttributes {

    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, 
            ErrorAttributeOptions options) {
        Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, options);
        
        // 添加自定義字段
        errorAttributes.put("locale", webRequest.getLocale().toString());
        errorAttributes.put("success", false);
        errorAttributes.put("version", "1.0");
        
        // 移除敏感信息
        errorAttributes.remove("trace");
        
        return errorAttributes;
    }
}

3.2 異常特定錯誤數據

@ControllerAdvice
public class CustomExceptionHandler {

    @ExceptionHandler(CustomException.class)
    public ResponseEntity<ErrorResponse> handleCustomException(
            CustomException ex, WebRequest request) {
        
        ErrorResponse errorResponse = new ErrorResponse(
            LocalDateTime.now(),
            ex.getErrorCode(),
            ex.getMessage(),
            request.getDescription(false));
            
        return new ResponseEntity<>(errorResponse, ex.getHttpStatus());
    }
}

@Data
@AllArgsConstructor
class ErrorResponse {
    private LocalDateTime timestamp;
    private String code;
    private String message;
    private String path;
}

四、高級定制技巧

4.1 區分API和頁面錯誤

@RestController
@RequestMapping("/api/**")
public class ApiErrorController {

    @RequestMapping("/error")
    public ResponseEntity<ApiError> handleApiError(HttpServletRequest request) {
        HttpStatus status = getStatus(request);
        ApiError apiError = new ApiError(status, 
            (String) request.getAttribute(RequestDispatcher.ERROR_MESSAGE));
        
        return new ResponseEntity<>(apiError, status);
    }
    
    private HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
        return statusCode != null ? HttpStatus.valueOf(statusCode) : HttpStatus.INTERNAL_SERVER_ERROR;
    }
}

4.2 錯誤頁面國際化

  1. 配置消息源:
spring.messages.basename=messages/errors
  1. 創建消息文件:
messages/
└── errors.properties
└── errors_zh_CN.properties
  1. 在模板中使用:
<p th:text="#{error.404.message}">Page not found</p>

4.3 錯誤日志記錄

@Component
public class CustomErrorController extends BasicErrorController {

    private static final Logger logger = LoggerFactory.getLogger(CustomErrorController.class);

    public CustomErrorController(ErrorAttributes errorAttributes) {
        super(errorAttributes, new ErrorProperties());
    }

    @Override
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        logError(request);
        return super.errorHtml(request, response);
    }

    private void logError(HttpServletRequest request) {
        Throwable error = getError(request);
        if (error != null) {
            logger.error("Error occurred: ", error);
        } else {
            logger.error("Error with status {} occurred", 
                request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE));
        }
    }
}

五、測試與驗證

5.1 單元測試

@SpringBootTest
@AutoConfigureMockMvc
class ErrorHandlingTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void test404Page() throws Exception {
        mockMvc.perform(get("/nonexistent"))
            .andExpect(status().isNotFound())
            .andExpect(view().name("error/404"));
    }

    @Test
    void testApiError() throws Exception {
        mockMvc.perform(get("/api/nonexistent")
                .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isNotFound())
            .andExpect(jsonPath("$.success").value(false))
            .andExpect(jsonPath("$.code").value("NOT_FOUND"));
    }
}

5.2 集成測試

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ErrorHandlingIntegrationTest {

    @LocalServerPort
    private int port;

    @Test
    void testErrorPage() {
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.getForEntity(
            "http://localhost:" + port + "/nonexistent", String.class);
        
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
        assertThat(response.getBody()).contains("Page Not Found");
    }
}

六、性能優化與最佳實踐

6.1 錯誤頁面緩存

@Configuration
public class ErrorPageConfig implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {

    @Override
    public void customize(ConfigurableWebServerFactory factory) {
        if (factory instanceof ConfigurableServletWebServerFactory) {
            ((ConfigurableServletWebServerFactory) factory).addErrorPages(
                new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
                new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"),
                new ErrorPage("/error")
            );
        }
    }
}

6.2 異步錯誤處理

@RestController
public class AsyncController {

    @GetMapping("/async")
    public CompletableFuture<String> asyncRequest() {
        return CompletableFuture.supplyAsync(() -> {
            if (Math.random() > 0.5) {
                throw new RuntimeException("Random error");
            }
            return "Success";
        }).exceptionally(ex -> {
            throw new ResponseStatusException(
                HttpStatus.INTERNAL_SERVER_ERROR, 
                "Async error occurred", ex);
        });
    }
}

6.3 安全考慮

  1. 生產環境隱藏堆棧信息:
server.error.include-stacktrace=never
server.error.include-message=never
server.error.include-binding-errors=never
  1. 自定義敏感信息過濾器:
@Component
public class ErrorSanitizer implements ErrorAttributes {

    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, 
            ErrorAttributeOptions options) {
        Map<String, Object> errorAttributes = // 獲取原始屬性
        
        // 清理敏感信息
        errorAttributes.values().removeIf(
            value -> value.toString().contains("password") || 
                    value.toString().contains("secret"));
        
        return errorAttributes;
    }
}

七、常見問題與解決方案

7.1 自定義錯誤頁面不生效

可能原因: 1. 文件位置不正確 2. 緩存問題 3. 優先級沖突

解決方案: 1. 確認文件位于resources/static/error/resources/templates/error/ 2. 清理瀏覽器緩存或使用spring.thymeleaf.cache=false 3. 檢查是否有自定義ErrorController覆蓋了默認行為

7.2 異常信息丟失

可能原因: 1. 過濾器/攔截器吞掉了異常 2. 異步處理未正確傳播異常

解決方案: 1. 檢查過濾器鏈中的異常處理 2. 確保異步方法正確傳播異常:

@Async
public CompletableFuture<String> asyncMethod() {
    try {
        // 業務邏輯
    } catch (Exception ex) {
        CompletableFuture<String> future = new CompletableFuture<>();
        future.completeExceptionally(ex);
        return future;
    }
}

7.3 國際化不工作

檢查步驟: 1. 確認messages.properties文件存在 2. 檢查spring.messages.basename配置 3. 驗證請求的Accept-Language

八、總結

SpringBoot提供了靈活的錯誤處理機制,開發者可以通過多種方式定制錯誤頁面和錯誤數據:

  1. 靜態錯誤頁面:簡單快速
  2. 動態模板頁面:靈活強大
  3. 完全自定義:最大控制權

最佳實踐建議: - 生產環境隱藏敏感信息 - 為API和頁面提供不同的錯誤處理 - 實現完善的錯誤日志記錄 - 考慮國際化需求 - 進行充分的錯誤處理測試

通過合理利用SpringBoot的錯誤處理功能,可以顯著提升應用的健壯性和用戶體驗。


本文共計約8650字,詳細介紹了SpringBoot錯誤頁面和數據定制的各個方面,從基礎配置到高級技巧,并提供了實用的代碼示例和解決方案。 “`

向AI問一下細節
推薦閱讀:
  1. 定制EditText
  2. 定制checkbox

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女