1. 简介
在 Spring 开发中,实现同一个目标往往有多种方式,比如精细化控制 HTTP 响应。
本文将重点介绍如何使用 ResponseEntity
来设置 HTTP 响应的响应体、状态码和响应头。
这是一个轻量但强大的工具,尤其适合需要对响应做细粒度控制的场景。掌握它,能让你在处理 REST 接口时更加游刃有余。
2. ResponseEntity 详解
ResponseEntity
✅ 代表完整的 HTTP 响应,包括:
- 状态码(Status Code)
- 响应头(Headers)
- 响应体(Body)
这意味着你可以完全掌控返回给客户端的内容。只要在接口方法中返回 ResponseEntity
,Spring 会自动帮你完成后续的序列化和输出。
它是一个泛型类,因此响应体可以是任意类型:
@GetMapping("/hello")
ResponseEntity<String> hello() {
return new ResponseEntity<>("Hello World!", HttpStatus.OK);
}
2.1 根据业务逻辑返回不同状态码
这是 ResponseEntity
最常见的用法之一。比如根据参数合法性返回 400
或 200
:
@GetMapping("/age")
ResponseEntity<String> age(@RequestParam("yearOfBirth") int yearOfBirth) {
if (isInFuture(yearOfBirth)) {
return new ResponseEntity<>(
"Year of birth cannot be in the future",
HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(
"Your age is " + calculateAge(yearOfBirth),
HttpStatus.OK);
}
⚠️ 踩坑提醒:HttpStatus
是枚举类型,建议始终使用 HttpStatus.OK
而不是 magic number 200
,代码可读性更强。
2.2 设置自定义响应头
除了状态码和响应体,你还可以轻松添加自定义 Header:
@GetMapping("/customHeader")
ResponseEntity<String> customHeader() {
HttpHeaders headers = new HttpHeaders();
headers.add("Custom-Header", "foo");
return new ResponseEntity<>("Custom header set", headers, HttpStatus.OK);
}
2.3 使用 Builder 模式(推荐写法)
ResponseEntity
提供了静态工厂方法和链式调用的 Builder 模式,代码更简洁、语义更清晰。
常见状态码的快捷方法:
ResponseEntity.ok("Hello World!");
ResponseEntity.notFound().build(); // 404
ResponseEntity.noContent().build(); // 204
ResponseEntity.badRequest().body("Invalid input");
ResponseEntity.created(URI.create("/users/123")).body("User created");
支持任意状态码:
ResponseEntity.status(HttpStatus.OK).body("Success");
ResponseEntity.status(418).body("I'm a teapot"); // RFC 2324 😂
链式设置 Header 和 Body:
@GetMapping("/age")
ResponseEntity<String> age(@RequestParam("yearOfBirth") int yearOfBirth) {
if (isInFuture(yearOfBirth)) {
return ResponseEntity.badRequest()
.body("Year of birth cannot be in the future");
}
return ResponseEntity.status(HttpStatus.OK)
.body("Your age is " + calculateAge(yearOfBirth));
}
✅ 推荐写法:
@GetMapping("/customHeader")
ResponseEntity<String> customHeader() {
return ResponseEntity.ok()
.header("Custom-Header", "foo")
.body("Custom header set");
}
⚠️ 注意:body()
方法返回的是 ResponseEntity
实例,必须作为链式调用的最后一个方法,否则后续调用无效。
2.4 与 @ControllerAdvice 配合处理异常
虽然 ResponseEntity
很强大,但你不应该在每个接口里手动处理所有异常。
Spring 3.2 引入了 @ControllerAdvice
+ @ExceptionHandler
的组合,用于全局统一处理异常并返回结构化错误信息。
例如:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleInvalidInput(IllegalArgumentException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
这样,你的接口代码可以更专注业务逻辑,异常处理交给切面统一兜底。详细实现可参考 Spring 异常处理最佳实践。
2.5 使用建议
✅ 适用场景:
- 需要返回非 200 状态码(如 201 Created、400 Bad Request)
- 需要添加自定义 Header(如分页信息、缓存控制)
- 动态决定响应状态
❌ 不建议滥用:
- 简单的
200 OK + JSON body
场景,直接返回对象即可,代码更干净 - 大量使用会导致控制器代码臃肿
📌 总结:功能强大,但别“杀鸡用牛刀”。
3. 替代方案对比
虽然 ResponseEntity
最灵活,但 Spring 还提供了其他更轻量的选择。根据场景选型,才能写出优雅的代码。
3.1 @ResponseBody:直接返回数据体
在传统 Spring MVC 中,接口默认返回视图(View)。但 REST 接口只需要数据。
使用 @ResponseBody
,Spring 会将方法返回值直接序列化为响应体,无需包装:
@GetMapping("/data")
@ResponseBody
String getData() {
return "Raw data";
}
💡 小知识:
@RestController = @Controller + @ResponseBody
,所以通常我们直接用@RestController
。
3.2 @ResponseStatus:声明式设置状态码
如果某个方法成功执行后应返回非 200 状态(如创建资源返回 201),可以用 @ResponseStatus
:
@PostMapping("/users")
@ResponseStatus(HttpStatus.CREATED)
User createUser(@RequestBody User user) {
return userService.save(user);
}
如果抛出异常,也可用于指定状态码:
@ResponseStatus(HttpStatus.NOT_FOUND)
public class UserNotFoundException extends RuntimeException {
}
Spring 会自动将该异常映射为 404
响应。
✅ 优点:声明式、简洁
⚠️ 缺点:状态码写死,无法动态控制
3.3 直接操作 HttpServletResponse(不推荐)
Spring 允许你直接注入 HttpServletResponse
对象进行底层操作:
@GetMapping("/manual")
void manual(HttpServletResponse response) throws IOException {
response.setHeader("Custom-Header", "foo");
response.setStatus(200);
response.getWriter().println("Hello World!");
}
❌ 为什么不推荐?
- 绕过了 Spring 的抽象层,失去了很多便利功能(如自动序列化、异常处理)
- 代码侵入性强,测试困难
- 与 Spring 编程模型背道而驰
📌 建议:除非特殊场景(如文件下载流),否则不要这么干。
4. 总结
方式 | 适用场景 | 是否推荐 |
---|---|---|
ResponseEntity |
需要控制状态码、Header、动态响应 | ✅ 推荐 |
@ResponseBody |
简单返回数据体 | ✅ 推荐(配合 @RestController ) |
@ResponseStatus |
固定状态码(成功或异常) | ✅ 推荐 |
HttpServletResponse |
底层流操作(如文件下载) | ⚠️ 仅特殊场景 |
✅ 最佳实践建议:
- 90% 的 REST 接口用
@RestController
+ 直接返回对象 - 需要精细控制时用
ResponseEntity
- 全局异常用
@ControllerAdvice
- 避免直接操作
HttpServletResponse
所有示例代码已托管至 GitHub:https://github.com/techblog-examples/spring-response-entity-demo