spring 中 HttpStatus 与 ResponseEntity
spring 中 HttpStatus 与 ResponseEntity
在Spring框架(尤其是Spring Web模块)中,org.springframework.http.HttpStatus
和org.springframework.http.ResponseEntity
是处理HTTP响应的核心类,二者配合使用可灵活控制HTTP响应的状态、头部和体内容。以下是详细解析:
一、HttpStatus
:HTTP状态码的枚举封装
1. 定义与作用
HttpStatus
是一个枚举类,封装了所有标准的HTTP状态码(如200、404、500等),每个枚举常量对应一个具体的HTTP状态,包含状态码的数字值、原因短语(Reason Phrase)等信息。
其核心作用是:提供标准化的HTTP状态码定义,避免硬编码数字(如200
),提高代码的可读性、可维护性和规范性。
2. 核心属性与方法
每个HttpStatus
枚举常量都包含以下关键信息(可通过方法获取):
- 状态码数值:如
200
、404
等,通过int value()
方法获取。 - 原因短语:状态码的文字描述(如
OK
、Not Found
),通过String getReasonPhrase()
方法获取。 - 状态码系列:HTTP状态码分为5类(1xx~5xx),通过
Series series()
方法获取所属系列(Series
是HttpStatus
的内部枚举,包含INFORMATIONAL
(1xx)、SUCCESSFUL
(2xx)、REDIRECTION
(3xx)、CLIENT_ERROR
(4xx)、SERVER_ERROR
(5xx))。
3. 常用枚举常量
-
2xx成功类:
OK
:200,请求成功(常用)。CREATED
:201,资源创建成功(如POST新增资源)。NO_CONTENT
:204,请求成功但无响应体(如DELETE删除资源)。
-
4xx客户端错误类:
BAD_REQUEST
:400,请求参数错误。UNAUTHORIZED
:401,未认证(如未登录)。FORBIDDEN
:403,权限不足。NOT_FOUND
:404,资源不存在。
-
5xx服务器错误类:
INTERNAL_SERVER_ERROR
:500,服务器内部错误。SERVICE_UNAVAILABLE
:503,服务不可用。
4. 实用方法
- 系列判断:如
is2xxSuccessful()
(是否为2xx成功状态)、is4xxClientError()
(是否为4xx客户端错误)等,简化状态码类型的判断。boolean isSuccess = HttpStatus.OK.is2xxSuccessful(); // true
- 状态码匹配:
matches(int statusCode)
判断当前枚举是否匹配指定的数字状态码。boolean isOk = HttpStatus.OK.matches(200); // true
5. 枚举常量详解
以下是HTTP状态码的作用和应用场景说明,按状态码类别整理为表格:
状态码 | 名称 | 作用 | 应用场景 |
---|---|---|---|
1xx 信息性状态码 | 表示服务器已接收请求,正在处理或等待进一步操作 | ||
100 | Continue | 服务器已接收请求头,允许客户端继续发送请求体 | 客户端发送大文件前,先确认服务器是否愿意接收(如上传大文件) |
101 | Switching Protocols | 服务器同意切换到客户端请求的协议 | WebSocket连接建立时,从HTTP协议升级到WebSocket协议 |
102 | Processing | 服务器正在处理请求,尚未完成 | 处理耗时请求(如复杂查询)时,告知客户端请求仍在处理中 |
103 | Early Hints | 服务器提前返回部分响应头,帮助客户端预加载资源 | 大型页面加载时,提前告知客户端缓存策略或预连接资源 |
103 | Checkpoint(已废弃) | 原用于断点续传标记 | 已被103 Early Hints替代,不再推荐使用 |
2xx 成功状态码 | 表示请求已成功被服务器接收、理解并处理 | ||
200 | OK | 请求成功,返回预期响应内容 | 绝大多数成功的GET、POST等请求(如获取数据、提交表单成功) |
201 | Created | 请求成功且创建了新资源 | POST请求创建资源(如新建用户、订单)时返回 |
202 | Accepted | 请求已被接受,但尚未处理完成 | 异步处理请求(如后台任务提交后,返回任务受理状态) |
203 | Non-Authoritative Information | 请求成功,但响应元数据来自第三方 | 代理服务器返回原始服务器的资源,但部分元数据被代理修改 |
204 | No Content | 请求成功,但无返回内容 | DELETE请求删除资源成功,或不需要返回内容的操作 |
205 | Reset Content | 请求成功,客户端应重置视图 | 表单提交后,告知客户端重置表单输入状态 |
206 | Partial Content | 部分请求成功,返回指定范围的资源 | 断点续传(如大文件下载时,客户端通过Range头请求部分内容) |
207 | Multi-Status | 多状态响应,包含多个资源的处理结果 | WebDAV协议中,批量操作多个资源时返回各资源的状态 |
208 | Already Reported | 资源已在其他请求中报告过 | WebDAV绑定操作中,避免重复报告同一资源状态 |
226 | IM Used | 服务器已执行GET请求,响应是对资源的修改 | 基于HTTP的增量更新(如版本控制系统返回资源修改部分) |
3xx 重定向状态码 | 表示客户端需要进一步操作才能完成请求 | ||
300 | Multiple Choices | 请求有多个可能的响应,需用户选择 | 资源有多个版本(如不同语言、格式)时,提供选择列表 |
301 | Moved Permanently | 资源已永久移动到新URL | 网站域名变更,旧URL永久重定向到新URL(客户端应更新书签) |
302 | Found | 资源临时移动到新URL | 临时跳转(如维护页面临时重定向到通知页,客户端下次仍用原URL) |
302 | Moved Temporarily(已废弃) | 同302 Found,旧称 | 已被302 Found替代,语义一致 |
303 | See Other | 请求完成后,需用GET方法访问新URL | POST表单提交成功后,重定向到结果页(避免刷新重复提交) |
304 | Not Modified | 资源未修改,客户端可使用缓存 | 客户端带ETag/Last-Modified头请求,服务器确认资源未变时返回 |
305 | Use Proxy(已废弃) | 资源必须通过指定代理访问 | 因安全问题已不推荐使用,现代浏览器多不支持 |
307 | Temporary Redirect | 临时重定向,保持原请求方法 | POST请求临时重定向时,仍用POST方法访问新URL(如临时服务器迁移) |
308 | Permanent Redirect | 永久重定向,保持原请求方法 | PUT请求永久重定向时,仍用PUT方法访问新URL(如API域名永久变更) |
4xx 客户端错误状态码 | 表示请求存在错误,服务器无法处理 | ||
400 | Bad Request | 请求语法错误或参数无效 | 提交的表单数据格式错误、JSON参数缺失等 |
401 | Unauthorized | 请求需要身份验证 | 未登录用户访问需授权的接口,或令牌过期/无效 |
402 | Payment Required | 预留状态码,需付费才能访问 | 极少使用,理论上用于付费内容访问(如订阅服务) |
403 | Forbidden | 服务器拒绝请求(已认证但无权限) | 登录用户访问无权限的资源(如普通用户访问管理员页面) |
404 | Not Found | 请求的资源不存在 | 访问不存在的URL(如拼写错误的页面、已删除的资源) |
405 | Method Not Allowed | 请求方法不被允许 | 用POST访问只支持GET的接口,或用DELETE访问只读资源 |
406 | Not Acceptable | 服务器无法提供客户端接受的格式 | 客户端通过Accept头要求JSON格式,但服务器只支持XML |
407 | Proxy Authentication Required | 需要代理服务器认证 | 客户端通过代理访问时,未通过代理的身份验证 |
408 | Request Timeout | 客户端请求超时 | 客户端发送请求过慢,服务器等待超时 |
409 | Conflict | 请求与服务器当前状态冲突 | 并发修改资源(如两人同时编辑文档,后提交者冲突) |
410 | Gone | 资源已永久删除,不再可用 | 原URL对应的资源被彻底删除,且无替代地址 |
411 | Length Required | 服务器要求Content-Length头,客户端未提供 | 客户端发送带请求体的请求(如POST)但未指定内容长度 |
412 | Precondition Failed | 请求头的前置条件不满足 | 客户端用If-Match验证资源版本,服务器发现版本不匹配 |
413 | Payload Too Large | 请求体过大,服务器拒绝处理 | 客户端上传超大文件,超过服务器限制 |
413 | Request Entity Too Large(已废弃) | 同413 Payload Too Large,旧称 | 已被413 Payload Too Large替代 |
414 | URI Too Long | 请求URI过长,服务器无法处理 | 客户端请求的URL包含过多参数或过长路径 |
414 | Request-URI Too Long(已废弃) | 同414 URI Too Long,旧称 | 已被414 URI Too Long替代 |
415 | Unsupported Media Type | 请求体的媒体类型不被支持 | 客户端发送application/xml数据,但服务器只支持application/json |
416 | Requested Range Not Satisfiable | Range请求的范围无效 | 客户端请求文件的第1000-2000字节,但文件仅500字节 |
417 | Expectation Failed | 服务器无法满足Expect请求头 | 客户端用Expect: 100-continue,但服务器不支持 |
418 | I’m a teapot | 服务器是茶壶,不能煮咖啡(玩笑性质) | 愚人节玩笑,多用于测试或彩蛋(如某些API的趣味响应) |
419 | Insufficient Space On Resource(已废弃) | 资源存储空间不足 | 旧版WebDAV使用,已被507 Insufficient Storage替代 |
420 | Method Failure(已废弃) | 请求方法执行失败 | 曾用于Spring框架,已弃用,建议用422或500替代 |
421 | Destination Locked(已废弃) | 目标资源被锁定 | 旧版WebDAV使用,已被423 Locked替代 |
422 | Unprocessable Entity | 请求语法正确,但语义错误 | 表单验证失败(如邮箱格式正确但已被注册) |
423 | Locked | 资源被锁定,无法操作 | WebDAV中,资源被其他用户锁定编辑时 |
424 | Failed Dependency | 因前置请求失败,当前请求无法完成 | WebDAV批量操作中,某资源处理失败导致后续请求依赖失败 |
425 | Too Early | 服务器不愿处理可能重复的请求 | 防止重放攻击(如客户端重复发送同一请求) |
426 | Upgrade Required | 客户端需升级协议 | 服务器仅支持HTTPS,客户端用HTTP访问时,要求升级 |
428 | Precondition Required | 服务器要求请求包含前置条件 | 服务器为防止并发修改,要求请求带If-Match等头 |
429 | Too Many Requests | 客户端请求过于频繁,触发限流 | API调用超过速率限制(如1分钟内请求超过100次) |
431 | Request Header Fields Too Large | 请求头过大,服务器拒绝处理 | 客户端发送的Cookie或其他头信息超过服务器限制 |
451 | Unavailable For Legal Reasons | 资源因法律原因不可用 | 资源被法院要求屏蔽(如版权侵权、违法内容) |
5xx 服务器错误状态码 | 表示服务器处理请求时发生错误 | ||
500 | Internal Server Error | 服务器内部通用错误 | 服务器代码异常(如NullPointerException) |
501 | Not Implemented | 服务器不支持请求的方法 | 客户端使用服务器未实现的HTTP方法(如PROPFIND) |
502 | Bad Gateway | 网关/代理收到无效响应 | 反向代理服务器从上游服务器收到错误响应 |
503 | Service Unavailable | 服务器暂时不可用 | 服务器维护、过载时,返回此状态(可带Retry-After头) |
504 | Gateway Timeout | 网关/代理等待上游响应超时 | 反向代理服务器等待后端服务响应超时 |
505 | HTTP Version Not Supported | 服务器不支持请求的HTTP版本 | 客户端用HTTP/3请求,服务器仅支持HTTP/1.1 |
506 | Variant Also Negotiates | 内容协商过程出错(循环引用) | 服务器配置错误,导致协商过程无限循环 |
507 | Insufficient Storage | 服务器存储不足 | WebDAV中,服务器无法存储上传的资源 |
508 | Loop Detected | 服务器检测到无限循环 | WebDAV中,处理请求时发现资源引用循环 |
509 | Bandwidth Limit Exceeded | 服务器带宽超限 | 非标准状态码,部分服务器用于表示带宽用尽 |
510 | Not Extended | 请求需要扩展,但服务器不支持 | 客户端请求的扩展功能未被服务器实现 |
511 | Network Authentication Required | 需要网络认证 | 公共WiFi中,用户未登录前访问互联网(跳转登录页) |
二、ResponseEntity
:HTTP响应的完整封装
1. 定义与作用
ResponseEntity<T>
是一个泛型类,用于封装HTTP响应的完整信息,包括:
- 响应状态码(通过
HttpStatus
指定); - 响应头(
HttpHeaders
); - 响应体(泛型
T
,即返回给客户端的数据)。
其核心作用是:在Spring MVC/WebFlux控制器中,作为方法返回值,精细化控制HTTP响应的各个部分(相比@ResponseBody
仅能控制响应体,ResponseEntity
更灵活)。
2. 核心结构
ResponseEntity
的核心组成:
private final T body
:响应体(可为null
,如204状态无体);private final HttpHeaders headers
:响应头(如Content-Type
、Authorization
等);private final HttpStatus statusCode
:响应状态码(HttpStatus
枚举)。
3. 常用创建方式
ResponseEntity
提供了多种静态工厂方法和构造器,简化创建过程:
-
直接指定状态码和响应体:
// 返回200 OK + 响应体 return ResponseEntity.ok(user); // 等价于 ResponseEntity.status(HttpStatus.OK).body(user)// 返回201 Created + 响应体 return ResponseEntity.status(HttpStatus.CREATED).body(newUser);
-
带响应头的响应:
HttpHeaders headers = new HttpHeaders(); headers.add("Location", "/users/123"); // 新增资源的URL return new ResponseEntity<>(user, headers, HttpStatus.CREATED);
-
无响应体的响应:
// 返回204 No Content(无响应体) return ResponseEntity.noContent().build();// 返回404 Not Found(无响应体) return ResponseEntity.notFound().build();
-
自定义响应头和状态:
return ResponseEntity.status(HttpStatus.FORBIDDEN).header("X-Error", "Permission denied").body("无权访问");
4. 核心方法
T getBody()
:获取响应体(可能为null
);HttpHeaders getHeaders()
:获取响应头;HttpStatus getStatusCode()
:获取响应状态码(HttpStatus
枚举);int getStatusCodeValue()
:获取状态码的数字值(如200)。
三、二者的关系与使用场景
1. 配合关系
HttpStatus
是ResponseEntity
的“状态码工具”:ResponseEntity
通过HttpStatus
枚举来指定响应的状态码,避免直接使用数字,保证规范性。
2. 典型使用场景
在Spring控制器中,当需要:
- 不仅返回数据(响应体),还需指定状态码(如创建资源返回201);
- 自定义响应头(如设置
Cache-Control
、Location
); - 返回无响应体的状态(如204、404);
此时必须使用ResponseEntity
,并结合HttpStatus
指定状态。
示例:
@RestController
@RequestMapping("/users")
public class UserController {@PostMappingpublic ResponseEntity<User> createUser(@RequestBody User user) {User savedUser = userService.save(user); // 保存用户HttpHeaders headers = new HttpHeaders();headers.setLocation(URI.create("/users/" + savedUser.getId())); // 资源位置// 返回201状态 + 响应体 + 自定义头return new ResponseEntity<>(savedUser, headers, HttpStatus.CREATED);}@GetMapping("/{id}")public ResponseEntity<User> getUser(@PathVariable Long id) {return userService.findById(id).map(ResponseEntity::ok) // 存在则返回200 + 数据.orElseGet(() -> ResponseEntity.notFound().build()); // 不存在返回404}
}
总结
HttpStatus
:标准化HTTP状态码的枚举,提供状态码、原因短语及系列判断,避免硬编码。ResponseEntity
:封装HTTP响应的完整信息(状态码、头、体),是Spring控制器中精细化控制响应的核心类。
二者配合使用,可优雅地处理各种HTTP响应场景,是Spring Web开发的基础工具。