@ResponseStatus注解是spring-web包中提供的一個注解,其主要作用就是為了改變HTTP響應的狀態碼,具有value、code、reason 三個屬性,如下:

一、@ResponseStatus注解用法
@ResponseStatus注解有兩種用法,一種是加載自定義異常類上,一種是加在目標方法中,當修飾一個類的時候,通常修飾的是一個異常類。
這里我們說一下加在目標方法上的這種情況,注解中有兩個參數,value屬性設置異常的狀態碼,reaseon是對於異常的描述,其實@ResponseStatus大部分情況下更適合於在自定義異常類或者目標方法上使用。
1、標注在@ControllerAdvice中
// controller
@GetMapping("/err") public Response errorTest(){ int i = 1 / 0; return new Response(401, "1/0", null); } // ExceptionController
@RestControllerAdvice public class ExceptionController { // 捕捉其他所有異常
@ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public Response globalException(HttpServletRequest request, Throwable ex) { return new Response(400,"1 / 0",null); } }
由於1 / 0 出現異常被我們捕獲之后返回我們自定義的狀態碼400,和自定義的結果。ResponseStatus就是設置了狀態碼400。
2、標注在controller方法上
(1)修改狀態碼
@RequestMapping(path = "/401") @ResponseStatus(value = HttpStatus.CREATED) public Response unauthorized() { return new Response(401, "Unauthorized", null); }
HttpStatus.CREATED 狀態碼為201,將原來請求狀態碼200改為201。

(2)使用reason
@RequestMapping(path = "/401") @ResponseStatus(value = HttpStatus.UNAUTHORIZED,reason = "no no no") public Response unauthorized() { return new Response(401, "Unauthorized", null); }
如果@ResponseStatus有reason屬性,@RequestMapping方法返回值都不處理了,直接返回服務器自帶的 ERROR 頁面,交互體驗比較差,建議不要使用。

3、標注在自定義的異常類上
使用時,先聲明一個自定義異常類,在自定義異常類上面加上@ResponseStatus注釋表示在系統運行期間,當拋出自定義異常的時候,使用@ResponseStatus注解中聲明的屬性和reason屬性將異常信息返回給客戶端,提高可讀性。
// MyException
@ResponseStatus(code = HttpStatus.PAYMENT_REQUIRED,reason = "this is MyException") public class MyException extends RuntimeException { public MyException() { } } // controller
@GetMapping("/err2") public Response errorTest2(){ throw new MyException(); }

二、底層實現原理
注解底層還是通過設置 response.setStatus 來實現的。在@RequestMapping方法執行完成,Spring解析返回值之前,進行了responseStatus設置。
代碼片段位於:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#setResponseStatus
this對象指當前的ServletInvocableHandlerMethod,看到 @ResponseStatus的reason不為空,就調用response.sendError ; reason為空,就調用setStatus方法僅僅設置響應狀態碼。

代碼片段位於:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle,發現如果ServletInvocableHandlerMethod的responseReason有值,也就是@ResponseStatus有reason屬性,@RequestMapping方法返回值都不處理了,直接返回;

也就是說只要有 @ResponseStatus 的 reason 屬性標注在 處理器 Controller 類或者方法上,比如響應狀態碼code設置為 404,reason設置為頁面沒找到 ,那 tomcat 展示界面是這樣大概,展示信息就是我們寫的reason屬性。
@ResponseStatus(code=A,reason=B)標注在 @RequestMapping方法上,作用效果與 response.sendError(A,B)是一樣的,所以需要慎用 reason 屬性。

二、@ResponseStatus的注意事項
1、當@ResponseStatus用在方法上,如果添加了reason屬性,且reason不為"",且code > 0(哪怕狀態碼是200),會對當前請求走錯誤處理。
@RequestMapping("/test") @ResponseStatus(reason="ok",code=HttpStatus.OK) public String test() { return "test"; }
原因:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod 類中,設置返回狀態。

io.undertow.servlet.handlers.ServletInitialHandler 類中,判斷錯誤碼。

2、返回狀態碼的其他翻案:返回狀態碼也可通過modelAndView.setStatus()實現
@RequestMapping(value = { "/test" }, method = RequestMethod.GET) public ModelAndView test() { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("test"); modelAndView.setStatus(HttpStatus.INTERNAL_SERVER_ERROR); return modelAndView; }
以上來源於這三篇文章的學習筆記:
https://www.cnblogs.com/lvbinbin2yujie/p/10575101.html
https://blog.csdn.net/Thinkingcao/article/details/110875494
https://blog.csdn.net/jumpe_17/article/details/118196644
