徹底解決SpringBoot 介面404異常響應~
來源:JAVA日知錄
大家好,我是飄渺。今天,我們將繼續探討DDD與微服務架構的系列主題。
在前一篇文章 優雅遠端呼叫,微服務中ACL與OpenFeign的絕佳配合!,一位粉絲提到在DailyMart中,關於Feign的error解碼器對404錯誤處理不夠友好,會返回空物件而不報錯。
實際上,這個問題並不是Feign解碼器的問題。
眾所周知,在Spring Boot中,當我們訪問一個不存在的介面時,會觸發404異常,介面呼叫會返回如下JSON格式的錯誤訊息:
{
"timestamp": "2023-09-23T03:36:50.503+00:00",
"status": 404,
"error": "Not Found",
"path": "/api/inventory/xxxx"
}
但是在DailyMart中,這個錯誤訊息會被全域性包裝類GlobalResponseBodyAdvice
處理,因此出現了以下奇怪的錯誤資訊:code碼為OK表示操作正常,但data訊息體卻表示404異常。由於這種情況,OpenFeign的異常解碼器無法正確處理。
{
"code": "OK",
"message": null,
"data": {
"timestamp": "2023-09-23T03:36:50.503+00:00",
"status": 404,
"error": "Not Found",
"path": "/api/inventory/xxxx"
},
"timestamp": 1695440210514
}
因此,問題的關鍵在於解決Spring Boot中404異常處理的問題,以便能夠返回正確的響應結果。
1. SpringBoot 的預設錯誤處理機制
Spring Boot預設為我們提供了BasicErrorController來處理全域性/error
請求。BasicErrorController提供兩種錯誤響應方式,一種是針對頁面請求的錯誤響應,另一種是針對JSON請求的錯誤響應。
2. 自定義錯誤響應
在SpringBoot中,BasicErrorController是由自動配置類ErrorMvcAutoConfiguration
負責載入。
@AutoConfiguration(before = WebMvcAutoConfiguration.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
@EnableConfigurationProperties({ ServerProperties.class, WebMvcProperties.class })
public class ErrorMvcAutoConfiguration {
...
@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,
ObjectProvider<ErrorViewResolver> errorViewResolvers) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
errorViewResolvers.orderedStream().toList());
}
}
根據上述配置,只要我們自己配置一個ErrorController,就可以覆蓋掉BasicErrorController的預設行為。下面的程式碼示例展示瞭如何透過繼承AbstractErrorController
並重寫error方法來自定義錯誤響應,以使其與專案整體風格一致:
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class CustomErrorController extends AbstractErrorController {
...
@RequestMapping
public Result<Void> error(HttpServletRequest request) {
return ResultFactory.fail(String.valueOf(status),message);
}
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
...
}
}
透過這種方式,當我們訪問不存在的方法時,將會返回符合預期的JSON響應結果:
{
"code": "404 NOT_FOUND",
"message": "No message available: /api/inventory/verify",
"data": null,
"timestamp": "1696598118098"
}
3. 微服務中的解決方案
上述方案在單服務中表現良好,但在微服務體系中,每個服務都需要建立一個獨立的CustomErrorController
,這顯然違反了DRY(Don't Repeat Yourself)原則。
在DailyMart中,我們封裝了一個公共模組dailymart-web-spring-boot-starter
,專門處理Web請求的邏輯,包括全域性響應包裝和異常處理。我們可以將CustomErrorController
放置在此模組中,並在配置類中載入該Controller。
/**
* 註冊SpringBoot預設異常處理器
*/
@Bean
public CusotmErrorController globalErrorController(ErrorAttributes errorAttributes){
return new CusotmErrorController(errorAttributes);
}
然而,這種做法在啟動服務時可能會引發以下異常:
Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'customerErrorController' method
com.jianzh5.dailymart.springboot.starter.web.CustomerErrorController#errorHtml(HttpServletRequest, HttpServletResponse)
to { [/error], produces [text/html]}: There is already 'basicErrorController' bean method
這是因為Spring Boot本身已經有一個處理/error
請求的控制器BasicErrorController,而我們又定義了一個CustomErrorController
來處理/error
請求。
3.1 解決方案
這個問題有兩種解決方案。
第一種解決方案是確保系統在啟動時能夠優先載入自定義的CustomErrorController
。
根據前文提到的BasicErrorController配置的條件註解,一旦定義了ErrorController就不會再載入BasicErrorController,所以只需要在自動配置類上加上@AutoConfiguration(before = ErrorMvcAutoConfiguration.class)
註解,確保CustomErrorController在BasicErrorController之前載入。
第二種解決方案是在載入CustomErrorController
時修改預設的BasicErrorController的攔截路徑。
如前所述,BasicErrorController的攔截路徑為@RequestMapping("${server.error.path:${error.path:/error}}")
,如果我們定義了error.path的值,它就會優先使用。因此,只需設定error.path
的值即可解決問題。
@PostConstruct
public void customizeErrorPath() {
// 修改 server.error.path 的值為自定義值
System.setProperty("error.path", "/deprecated/error");
}
小結
透過本文,我們探討了Spring Boot中的404異常處理問題,以及如何透過自定義ErrorController來解決這一問題。特別是在微服務架構中,我們介紹瞭如何利用共享模組的方法來更有效地管理異常處理。希望這些實踐經驗對您有所幫助,提高了您在微服務開發中處理異常情況的能力。我們非常歡迎各位讀者提出寶貴的意見和建議,以進一步完善這個系列文章。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024924/viewspace-2987463/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 徹底理解安卓應用無響應機制安卓
- 踩坑記:gRPC 異常響應RPC
- 5個點徹底搞清楚SpringBoot註解Spring Boot
- 徹底解決Python編碼問題Python
- SpringBoot錯誤處理機制以及自定義異常響應原理解析Spring Boot
- SpringBoot-java.lang.IllegalArgumentException: Not a managed type異常問題解決方法Spring BootJavaException
- springboot接收Date型別資料異常與解決辦法Spring Boot型別
- Ionic異常及解決
- 徹底解決Linux下mongodb的安裝LinuxMongoDB
- 徹底解決Hive小檔案問題Hive
- 介面詭異的404問題記錄
- 一站式統一返回值封裝、異常處理、異常錯誤碼解決方案—最強的Sping Boot介面優雅響應處理器封裝boot
- Laravel 修改驗證異常的響應格式Laravel
- ElementPlus Upload上傳檔案只能上傳一次,第二次無響應,徹底解決。
- springboot自定義異常Spring Boot
- SpringCloud BeanCurrentlyInCreationException 異常解決方案SpringGCCloudBeanException
- SpringBoot專案實戰(7):自定義異常處理介面Spring Boot
- 徹底透析SpringBoot jar可執行原理Spring BootJAR
- 如何徹底解決pip install慢的問題
- Spring Boot優雅地處理404異常Spring Boot
- CentOS 常見異常及解決辦法CentOS
- @ControllerAdvice 全域性異常響應頁面和 JSONControllerJSON
- SpringBoot+ShardingSphere徹底解決生產環境資料庫欄位加解密問題Spring Boot資料庫解密
- 這次,徹底弄懂介面及抽象類抽象
- No bean named 'cacheManager' availablej 異常解決BeanAI
- SpringBoot中異常處理Spring Boot
- springboot 全域性異常攔截器,友好異常提示Spring Boot
- SpringBoot介面 - 如何優雅的寫Controller並統一異常處理?Spring BootController
- 【異常解決】springBoot單元測試es報錯availableProcessors is already set to [12], rejecting [12]Spring BootAI
- 關於SpringMVC的HttpMediaTypeNotSupportedException異常解決SpringMVCHTTPException
- [持續更新]hive異常解決方案Hive
- springboot全域性異常處理Spring Boot
- SpringBoot統一異常處理Spring Boot
- Laravel 打造適合 API 的異常處理響應格式LaravelAPI
- 易優cms404頁面 丟擲HttpException異常HTTPException
- macOS解除安裝應用不徹底Mac
- 解決SpringBoot頁面localhost 404問題,即Whitelabel Error Page問題Spring BootlocalhostError
- ChatGPT,我徹徹底底淪陷了!ChatGPT