Spring Boot中自定義404異常處理問題學習筆記

1. 問題背景

在Spring Boot項目中,需要手動返回404異常給前端。為此,我創建了一個自定義的404異常類UnauthorizedAccessException,并在全局異常處理器GlobalExceptionHandler中處理該異常。然而,在使用Postman測試時,返回的仍然是500錯誤,而不是預期的404錯誤。

2. 代碼實現

2.1 自定義404異常類

package cn.jbolt.config.exception;import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;/*** 自定義無權限訪問的異常*/
@ResponseStatus(HttpStatus.NOT_FOUND)
public class UnauthorizedAccessException extends RuntimeException {private final HttpStatus status;public UnauthorizedAccessException(String message) {super(message);this.status = HttpStatus.NOT_FOUND;}public HttpStatus getStatus() {return status;}
}

2.2 全局異常處理器

package cn.jbolt.config.exception;import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(UnauthorizedAccessException.class)public ResponseEntity<String> handleUnauthorizedAccessException(UnauthorizedAccessException ex) {System.out.println("UnauthorizedAccessException-------------------------: " + ex.getMessage());HttpStatus status = ex.getStatus();String message = ex.getMessage();return new ResponseEntity<>(message, status);}
}

2.3 過濾器中拋出自定義異常

package cn.jbolt.teaching_tools.school;import cn.jbolt.config.exception.UnauthorizedAccessException;
import cn.jbolt.teaching_tools.school.entity.School;
import cn.jbolt.teaching_tools.school.service.SchoolService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SchoolContextFilter implements Filter {@Autowiredprivate SchoolService schoolService;@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;try {// 從域名獲取學校信息String serverName = httpRequest.getServerName();String[] domainParts = serverName.split("\\.");if (domainParts.length >= 3) {String subdomain = domainParts[0];// 查詢學校IDSchool school = schoolService.getByDomain(subdomain);if (school != null) {// 設置到SchoolContextHolder和請求屬性SchoolContextHolder.setSchoolId(school.getId().toString());} else {// 如果找不到學校,拋出異常throw new UnauthorizedAccessException("異常域名");}} else {// 如果不是二級域名,拋出異常throw new UnauthorizedAccessException("異常域名");}chain.doFilter(request, response);} catch (UnauthorizedAccessException ex) {// 手動處理異常,寫入響應httpResponse.setStatus(HttpStatus.NOT_FOUND.value());httpResponse.setContentType("application/json;charset=UTF-8");httpResponse.getWriter().write("{\"timestamp\": " + System.currentTimeMillis() + ", \"status\": 404, \"error\": \"Not Found\", \"message\": \"" + ex.getMessage() + "\", \"path\": \"" + httpRequest.getRequestURI() + "\"}");} finally {SchoolContextHolder.clear();}}
}

3. 問題分析

3.1?Filter拋出的異常未被Spring MVC捕獲

在Spring Boot中,Filter是Servlet API的一部分,而Spring MVC的全局異常處理器(@ControllerAdvice@RestControllerAdvice)只能捕獲Spring MVC控制器中拋出的異常。因此,當Filter拋出異常時,Spring MVC的全局異常處理器無法捕獲,導致返回了500錯誤。

3.2?@RestControllerAdvice未正確掃描

如果GlobalExceptionHandler類所在的包沒有被Spring Boot掃描到,它將無法生效。確保GlobalExceptionHandler類所在的包在Spring Boot的掃描路徑內。

3.3 Spring Boot的默認錯誤處理機制

Spring Boot的默認錯誤處理機制可能會覆蓋自定義的異常處理邏輯。可以通過配置application.propertiesapplication.yml文件來調整默認錯誤處理行為。

4. 解決方案

4.1 在Filter中手動處理異常

由于Filter拋出的異常無法被Spring MVC的全局異常處理器捕獲,因此需要在Filter中手動處理異常,將異常信息寫入響應中。具體實現如下:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;try {// 從域名獲取學校信息String serverName = httpRequest.getServerName();String[] domainParts = serverName.split("\\.");if (domainParts.length >= 3) {String subdomain = domainParts[0];// 查詢學校IDSchool school = schoolService.getByDomain(subdomain);if (school != null) {// 設置到SchoolContextHolder和請求屬性SchoolContextHolder.setSchoolId(school.getId().toString());} else {// 如果找不到學校,拋出異常throw new UnauthorizedAccessException("異常域名");}} else {// 如果不是二級域名,拋出異常throw new UnauthorizedAccessException("異常域名");}chain.doFilter(request, response);} catch (UnauthorizedAccessException ex) {// 手動處理異常,寫入響應httpResponse.setStatus(HttpStatus.NOT_FOUND.value());httpResponse.setContentType("application/json;charset=UTF-8");httpResponse.getWriter().write("{\"timestamp\": " + System.currentTimeMillis() + ", \"status\": 404, \"error\": \"Not Found\", \"message\": \"" + ex.getMessage() + "\", \"path\": \"" + httpRequest.getRequestURI() + "\"}");} finally {SchoolContextHolder.clear();}
}

4.2 確保@RestControllerAdvice被正確掃描

確保GlobalExceptionHandler類所在的包在Spring Boot的掃描路徑內。例如:

@SpringBootApplication(scanBasePackages = "cn.jbolt")
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

4.3 調整Spring Boot的默認錯誤處理機制

可以通過配置application.propertiesapplication.yml文件來調整默認錯誤處理行為。例如:

server.error.include-stacktrace=never
server.error.include-message=always
server.error.include-binding-errors=always
server.error.include-exception=false

5. 測試驗證

5.1 測試用例

使用Postman測試以下兩種場景:

  1. 正常請求:請求的域名和路徑符合預期,應返回正常響應。

  2. 異常請求:請求的域名不符合預期,應返回404錯誤。

5.2 測試結果

  • 正常請求:返回正常響應。

  • 異常請求:返回404錯誤,響應內容如下:

    {"timestamp": 1745483881203,"status": 404,"error": "Not Found","message": "異常域名","path": "/auth/login"
    }

6. 注意事項

6.1 異常處理的優先級

如果項目中有多個全局異常處理器,可能會導致異常處理邏輯被覆蓋。確保自定義的異常處理邏輯優先級高于其他全局異常處理器。

6.2 日志記錄

在全局異常處理器中添加日志記錄,方便調試和排查問題。例如:

@ExceptionHandler(UnauthorizedAccessException.class)
public ResponseEntity<String> handleUnauthorizedAccessException(UnauthorizedAccessException ex) {System.out.println("UnauthorizedAccessException-------------------------: " + ex.getMessage());HttpStatus status = ex.getStatus();String message = ex.getMessage();return new ResponseEntity<>(message, status);
}

6.3 響應格式的統一

確保返回的響應格式與前端的要求一致。可以使用統一的錯誤響應類來封裝錯誤信息,例如:

public class ErrorResponse {private Long timestamp;private int status;private String error;private String message;private String path;// Getters and Setters
}

然后在Filter中返回統一的錯誤響應:

httpResponse.getWriter().write(new ObjectMapper().writeValueAsString(new ErrorResponse(System.currentTimeMillis(), 404, "Not Found", ex.getMessage(), httpRequest.getRequestURI())));

7. 總結

通過在Filter中手動處理異常,確保返回給前端的響應是正確的404錯誤,而不是500錯誤。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80354.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80354.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80354.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

你學會了些什么220622?--搭建UI自動化

jenkins訪問地址&#xff1a;http://192.168.82.129:8080/ 賬號密碼&#xff1a;admin/a123456a ***** 什么是UI自動化** 使用工具或者腳本對需要測試的軟件的前端界面在預設的條件下&#xff0c;在已有的測試數據下運行系統或者應用程序&#xff0c;并獲取其前端頁面UI顯示的…

【2025計算機網絡-面試常問】http和https區別是什么,http的內容有哪些,https用的是對稱加密還是非對稱加密,流程是怎么樣的

HTTP與HTTPS全面對比及HTTPS加密流程詳解 一、HTTP與HTTPS核心區別 特性HTTPHTTPS協議基礎明文傳輸HTTP SSL/TLS加密層默認端口80443加密方式無加密混合加密&#xff08;非對稱對稱&#xff09;證書要求不需要需要CA頒發的數字證書安全性易被竊聽、篡改、冒充防竊聽、防篡改…

JavaFX 第一篇 Hello World

1、簡介 JavaFX 是一個用于構建客戶端應用程序的 Java 庫&#xff0c;作為 Java 標準庫的一部分&#xff08;JDK 8 到 10&#xff09;&#xff0c;從 JDK 11 開始&#xff0c;JavaFX 將以獨立模塊發布&#xff0c;將不再包含在 JDK標準庫中&#xff0c;他是 Java 應用程序開發的…

SQL實戰:02之連續數問題求解

文章目錄 概述題目:體育館的人流量題解步驟一&#xff1a;構造出一個連續序列步驟二&#xff1a;找出符合條件的組的序號步驟三&#xff1a;fetch結果&#xff0c;使用內連接過濾出符合條件的記錄。完整SQL 題目二&#xff1a;連續出現的數字題解步驟一&#xff1a;分區并構建連…

STM32 的 GPIO和中斷

GPIO的簡單介紹 內部結構 施密特觸發器&#xff08;TTL肖特基觸發器&#xff09; 的工作原理&#xff1a; 施密特觸發電路&#xff08;簡稱&#xff09;是一種波形整形電路&#xff0c;當任何波形的信號進入電路時&#xff0c;輸出在正、負飽和之間跳動&#xff0c;產生方波或…

Server - 優雅的配置服務器 Bash 環境(.bashrc)

歡迎關注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/147335592 免責聲明&#xff1a;本文來源于個人知識與公開資料&#xff0c;僅用于學術交流&#xff0c;歡迎討論&#xff0c;不支持轉載。 登錄服…

使用PyTorch實現圖像增廣與模型訓練實戰

本文通過完整代碼示例演示如何利用PyTorch和torchvision實現常用圖像增廣方法&#xff0c;并在CIFAR-10數據集上訓練ResNet-18模型。我們將從基礎圖像變換到復雜數據增強策略逐步講解&#xff0c;最終實現一個完整的訓練流程。 一、圖像增廣基礎操作 1.1 準備工作 #matplotli…

解決Mac 安裝 PyICU 依賴失敗

失敗日志&#xff1a; 解決辦法 1、使用 homebrew 安裝相關依賴 brew install icu4c 安裝完成后&#xff0c;設置環境變量 echo export PATH"/opt/homebrew/opt/icu4c77/bin:$PATH" >> ~/.zshrcecho export PATH"/opt/homebrew/opt/icu4c77/sbin:$PATH…

Springboot后端查詢參數接收

1.實現方式 假設前端發送的接口&#xff1a; /users?nameJohn&age30 后端怎么接收里面的name和age呢&#xff1f;以及再發別的參數后端怎么接收呢&#xff1f; 1.比較簡單的方式 當控制器方法的參數類型是簡單類型&#xff08;如 String、Integer、Long 等&#xff09…

桌面應用中VUE使用新瀏覽器窗口打開頁面

1、瀏覽器應用忽略此方式&#xff0c;可任意方式打開。針對桌面應用設置 newWindowClick(){try {this.fileUrl "";this.params.year ""this.params.date ""axios({method: post,url: /url/pdf/preview,data: this.params,}).then(res> {t…

華為手機怎么進行音頻降噪?音頻降噪技巧分享:提升聽覺體驗

在當今數字化時代&#xff0c;音頻質量對于提升用戶體驗至關重要&#xff0c;無論是在通話、視頻錄制還是音頻文件播放中&#xff0c;清晰的音頻都能帶來更佳的聽覺享受。 而華為手機憑借其強大的音頻處理技術&#xff0c;為用戶提供了多種音頻降噪功能&#xff0c;幫助用戶在…

【數據可視化-22】脫發因素探索的可視化分析

?? 博主簡介:曾任某智慧城市類企業算法總監,目前在美國市場的物流公司從事高級算法工程師一職,深耕人工智能領域,精通python數據挖掘、可視化、機器學習等,發表過AI相關的專利并多次在AI類比賽中獲獎。CSDN人工智能領域的優質創作者,提供AI相關的技術咨詢、項目開發和個…

青少年編程與數學 02-018 C++數據結構與算法 06課題、樹

青少年編程與數學 02-018 C數據結構與算法 06課題、樹 一、樹(Tree)1. 樹的定義2. 樹的基本術語3. 常見的樹類型4. 樹的主要操作5. 樹的應用 二、二叉樹(Binary Tree)1. 二叉樹的定義2. 二叉樹的基本術語3. 二叉樹的常見類型4. 二叉樹的主要操作5. 二叉樹的實現代碼說明輸出示例…

【論文閱讀】Visual Instruction Tuning

文章目錄 導言1、論文簡介2、論文主要方法3、論文針對的問題4、論文創新點總結 導言 本論文介紹了一個新興的多模態模型——LLaVA&#xff08;Large Language and Vision Assistant&#xff09;&#xff0c;旨在通過指令調優提升大型語言模型&#xff08;LLM&#xff09;在視覺…

【學習筆記】Cadence電子設計全流程(三)Capture CIS 原理圖繪制(下)

【學習筆記】Cadence電子設計全流程&#xff08;三&#xff09;Capture CIS 原理圖繪制&#xff08;下&#xff09; 3.16 原理圖中元件的編輯與更新3.17 原理圖元件跳轉與查找3.18 原理圖常見錯誤設置于編譯檢查3.19 低版本原理圖文件輸出3.20 原理圖文件的鎖定與解鎖3.21 Orca…

js使用IntersectionObserver實現目標元素可見度的交互

文章目錄 1、前言2、代碼實現3、使用場景4、兼容性5、成熟的Hooks推薦 1、前言 IntersectionObserver 是瀏覽器原生提供的一個Api。可以"觀察"我們的元素是否可見&#xff0c;原理是判斷目標元素與可見區域的交叉比例&#xff0c;所以也被稱為"交叉觀察器"…

linux 中斷子系統 層級中斷編程

虛擬中斷控制器代碼&#xff1a; #include<linux/kernel.h> #include<linux/module.h> #include<linux/clk.h> #include<linux/err.h> #include<linux/init.h> #include<linux/interrupt.h> #include<linux/io.h> #include<linu…

蝦皮(Shopee)商品詳情 API 接口概述及 JSON 數據返回參考

前言 一、接口概述 Shopee 商品詳情 API 接口是 Shopee 平臺為開發者提供的&#xff0c;用于獲取商品詳細信息的接口服務。通過該接口&#xff0c;開發者可以獲取商品的標題、價格、庫存、描述、圖片、規格參數、銷量、評價等詳細信息。這些數據為電商數據分析、商品比價工具…

three.js中的instancedMesh類優化渲染多個同網格材質的模型

three.js小白的學習之路。 在上上一篇博客中&#xff0c;簡單驗證了一下three.js中的網格共享。寫的時候就有一些想法&#xff0c;如果說某個場景中有一萬棵樹&#xff0c;這些樹共享一個geometry和material&#xff0c;有沒有好的辦法將其進行一定程度上的渲染優化&#xff0…

MySQL-自定義函數

自定義函數 函數的作用 mysql數據庫中已經提供了內置的函數&#xff0c;比如&#xff1a;sum&#xff0c;avg&#xff0c;concat等等&#xff0c;方便我們日常的使用&#xff0c;當需要時mysql支持定義自定義的函數&#xff0c;方便與我們對于需用復用的功能進行封裝。 基本…