1. 简介

在 Spring MVC 中,有多种方式可以设置 HTTP 响应的状态码

本文将介绍其中最简单直接的一种:使用 @ResponseStatus 注解。✅

这个注解虽然小,但在控制 REST 接口返回状态时非常实用,尤其适合那些希望代码简洁、语义清晰的开发者。踩坑多了你会发现,状态码管理混乱是线上问题的常见诱因之一。


2. 用于 Controller 方法

默认情况下,当一个接口成功执行后,Spring 会返回 HTTP 200(OK)状态码。

但我们可以通过 @ResponseStatus 注解来显式指定某个 Controller 方法的响应状态码。该注解提供两个等价参数用于指定状态:

  • code
  • value

⚠️ 二者作用完全相同,可互换使用,推荐统一用 code 提高可读性。

举个“经典”的例子(RFC 2324 开玩笑用的):

@ResponseStatus(HttpStatus.I_AM_A_TEAPOT)
void teaPot() {}

调用这个接口时,客户端会收到 418 I'm a teapot 状态码。虽然不实用,但说明了用法足够灵活。

自定义错误信息

你还可以通过 reason 参数附加一条错误描述:

@ResponseStatus(HttpStatus.BAD_REQUEST, reason = "Some parameters are invalid")
void onIllegalArgumentException(IllegalArgumentException exception) {}

⚠️ 但注意:只要设置了 reason,Spring 就会调用 HttpServletResponse.sendError(),这会导致:

  • 返回的是 HTML 错误页面
  • 不适合用于 RESTful API(我们通常期望返回 JSON)

所以,在构建前后端分离或对外提供的 REST 接口时,不要设置 reason 字段

执行前提

@ResponseStatus 只有在被标记的方法正常完成(未抛出异常) 时才会生效。

换句话说:方法没出错,才走这个注解定义的状态码逻辑。


3. 与异常处理器结合使用

除了用于正常流程,@ResponseStatus 更常见的用途是配合异常处理机制,将 Java 异常映射为对应的 HTTP 状态码。

Spring 支持以下三种方式实现这一功能:

  1. 使用 @ExceptionHandler 在控制器内处理异常
  2. 使用 @ControllerAdvice 全局统一处理
  3. 直接在自定义异常类上标注 @ResponseStatus

前两种需要编写异常处理方法,细节可参考 Baeldung 的 Spring REST 异常处理文章。这里重点讲第三种——最简单粗暴且高内聚的方式

方式一:@ExceptionHandler

@ExceptionHandler(CustomException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public void handleCustomException() {
    // 日志记录、监控上报等
}

这种方式适用于需要对不同异常做差异化处理的场景。

方式二:@ControllerAdvice

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ValidationException.class)
    @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
    public void handleValidation(ValidationException e) {
        // 统一处理校验异常
    }
}

适合全局异常拦截,是现代 Spring Boot 项目中最常见的做法。

方式三:直接标记异常类(推荐)

如果你的异常和状态码之间有一一对应关系,且不需要动态响应体,那最干净的做法是——**直接在异常类上加 @ResponseStatus**:

@ResponseStatus(code = HttpStatus.BAD_REQUEST)
class CustomException extends RuntimeException {}

这样,只要这个异常被 Spring 捕获(无论是否在 @ControllerAdvice 中处理),框架就会自动将其转换为指定的 HTTP 状态码。

注意事项 ⚠️

  • 一旦异常类被 @ResponseStatus 标记,Spring **总会调用 sendError()**,即使没有设置 reason
  • 这意味着:返回的是容器默认的错误页(HTML),不适合 REST 接口
  • 如果你希望返回 JSON 格式的错误响应,应避免使用此方式,转而使用 @ExceptionHandler 手动构造响应体 ✅

继承行为

  • 子类会继承父类的 @ResponseStatus 配置
  • 除非子类自己也标注了 @ResponseStatus,此时以子类为准

例如:

@ResponseStatus(HttpStatus.BAD_REQUEST)
class BusinessException extends RuntimeException {}

class InvalidOrderException extends BusinessException {} 
// 自动获得 400 状态码

4. 总结

@ResponseStatus 是一个轻量级但强大的工具,适用于多种场景下的 HTTP 状态码设置:

使用场景 是否推荐 说明
正常接口返回非 200 状态 ✅ 推荐 如创建资源返回 201
异常类直接标注状态码 ⚠️ 谨慎 会触发 sendError(),返回 HTML
REST API 错误响应 ❌ 不推荐直接用 应结合 @ExceptionHandler 返回 JSON

✅ 最佳实践建议:

  • 对于 REST 接口,优先使用 @ControllerAdvice + @ExceptionHandler,手动控制响应格式
  • 若只是想改变成功状态码(如 POST 返回 201),直接在方法上加 @ResponseStatus 简单高效
  • 自定义异常类上加 @ResponseStatus 仅适用于非 REST 场景或已有错误页体系的项目

示例代码已托管至 GitHub:https://github.com/baeldung/spring-web-modules/tree/master/spring-mvc-basics-5


原始标题:Using @ResponseStatus to Set HTTP Status Code | Baeldung