文章目录
- 一、ResponseEntity深入
- 简介
- 使用场景
- 1、场景一
- 2、场景二
- 3、场景三:
- 父类HttpEntity
- ResponseEntity的研究
- 1、ResponseEntity的属性
- 2、ResponseEntity的6个构造方法:
- 3、HttpStatus
- 简介
- HTTP状态码
- 属性
- 构造方法
- 其他方法
- 序列号
- 4、ResponseEntity的其他方法
- 5、BodyBuilder和HeadersBuilder介绍
- 6、静态方法
一、ResponseEntity深入
简介
ResponseEntity可以表示整个HTTP响应,包括:状态码、头部信息以及响应体。ResponseEntity的API:
public class ResponseEntity<T> extends HttpEntity<T> {
}
接下来看看它的官方介绍:
Extension of HttpEntity that adds an HttpStatus status code. Used in RestTemplate as well as in @Controller methods.
HttpEntity的扩展,添加了一个HttpStatus状态代码。在RestTemplate和@Controller方法中使用。
使用场景
1、场景一
In RestTemplate, this class is returned by getForEntity() and exchange():
在RestTemplate中,这个类由getForEntity()和exchange()返回
【说明】RestTemplate:是Spring提供的模板工具类,堆基于HTTP的客户端进行了封装,并且实现了对象与json的序列化和反序列化.
下面看一下getForEntity(),传入URL和响应的类,就会返回一个ResponseEntity
//通过对URL执行GET来检索表示。响应被转换并存储在ResponseEntity中。
//Retrieve a representation by doing a GET on the URL . The response is converted and stored in an ResponseEntity.
<T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;
使用:
ResponseEntity<String> entity = template.getForEntity("https://example.com", String.class);
String body = entity.getBody();
MediaType contentType = entity.getHeaders().getContentType();
HttpStatus statusCode = entity.getStatusCode();
2、场景二
This can also be used in Spring MVC as the return value from an @Controller method:
这也可以在Spring MVC中用作@Controller方法的返回值:
使用:
@RequestMapping("/handle")
public ResponseEntity<String> handle() {
URI location = ...;
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setLocation(location);
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}
3、场景三:
Or, by using a builder accessible via static methods:
或者,可以通过静态方法的构建器进行访问
使用:
@RequestMapping("/handle")
public ResponseEntity<String> handle() {
URI location = ...;
return ResponseEntity.created(location).header("MyResponseHeader", "MyValue").body("Hello World");
}
父类HttpEntity
Represents an HTTP request or response entity, consisting of headers and body.
HttpEntity:表示HTTP请求或响应实体,由报头和正文组成。
这就证实了之前的说明,ResponseEntity是HttpEntity的扩展,在HttpEntity的基础之上添加了状态码。
它有两个属性:报头和身体
private final HttpHeaders headers;
//身体允许为空
@Nullable
private final T body;
//同时定义了一个空的HttpEntity,没有报头和身体
public static final HttpEntity<?> EMPTY = new HttpEntity<>();
有4个构造方法:
//创建一个空的HttpEntity
protected HttpEntity() {this(null, null);}
//创建了一个有身体的HttpEntity,但是没有报头
public HttpEntity(T body) {this(body, null);}
//创建了一个有报头但是没有身体的HttpEntity
public HttpEntity(MultiValueMap<String, String> headers) {this(null, headers);}
//创建了一个既有身体又有报头的HttpEntity
public HttpEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers) {
this.body = body;
this.headers = HttpHeaders.readOnlyHttpHeaders(headers != null ? headers : new HttpHeaders());
}
剩下的都是get/set方法,用于获取身体和报头;判断是否有身体等方法,在这里就赘述了。
接下来好好研究ResponseEntity。
ResponseEntity的研究
从上面的结论中已经知道,ResponseEntity继承自HttpEntity,以及ResponseEntity的使用场景,接下来好好研究它内部的方法,首先看看它的属性有哪些
1、ResponseEntity的属性
状态码 status code.
private final Object status;
2、ResponseEntity的6个构造方法:
//1、创建一个仅仅只有状态码的ResponseEntity
public ResponseEntity(HttpStatus status) {
this(null, null, status);
}
//2、创建一个有身体和状态码的ResponseEntity
public ResponseEntity(@Nullable T body, HttpStatus status) {
this(body, null, status);
}
//3、创建一个有报头和状态码的ResponseEntity
public ResponseEntity(MultiValueMap<String, String> headers, HttpStatus status) {
this(null, headers, status);
}
//4、创建一个有身体、报头和状态码的ResponseEntity
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatus status) {
this(body, headers, (Object) status);
}
//5、Create a {@code ResponseEntity} with a body, headers, and a raw status code.
// @param rawStatus the status code value
//创建一个有身体、报头、自己给定状态码 的ResponseEntity
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, int rawStatus) {
this(body, headers, (Object) rawStatus);
}
/**6、私有构造器
* Private constructor.
*/
private ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, Object status) {
super(body, headers);
Assert.notNull(status, "HttpStatus must not be null");
this.status = status;
}
3、HttpStatus
简介
从上面的构造器中可以看到状态码都是使用了:HttpStatus中的状态码,接下来咱们看看又是一个什么鬼
/**
Enumeration of HTTP status codes.
The HTTP status code series can be retrieved via series().
HTTP状态代码系列可以通过series()检索。
*/
public enum HttpStatus {...}
HTTP状态码
HttpStatus是HTTP状态码的枚举,看看里面都有些啥内容,在这之前,我给大家看一份HTTP的官方文档
有时间看看HTTP协议的内容
Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content 超文本传输协议(HTTP/1.1):语义和内容
https://datatracker.ietf.org/doc/html/rfc7231#section-6.2.1
超文本传输协议(HTTP)是一种无状态的应用用于分布式、协作、超文本信息的级别协议系统。本文档定义了HTTP/1.1消息的语义,如请求方法,请求报头字段,响应状态码,响应报头字段,以及消息(元数据和正文内容)和内容机制谈判
这是一个互联网标准跟踪文档。
这里面会具体介绍HTTP状态码,如果你需要学习其他的内容,自己有空去看看。
下面是常见的状态码,给大家罗列出来:
• 1XX:服务器收到请求,需要请求者继续执行操作
• 100 Continue :继续。客户端应继续其请求
• 101 Switching Protocols :切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
• 2XX :成功,操作被成功接收并处理
• 200 OK :请求已成功。
• 201 Created :201 (Created)状态码表示请求已经被创建完成并导致一个或多个新的资源创建。
• 202 Accepted:已接受。已经接受请求,但未处理完成
• 204 No Content: 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
• 。。。。
• 3XX:重定向,需要进一步的操作以完成请求
• 4XX:客户端错误,请求包含语法错误或无法完成请求
• 400 Bad Request:客户端请求的语法错误,服务器无法理解
• 404 Not Found:服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
• 5XX:服务器错误,服务器在处理请求的过程中发生了错误
• 500 Internal Server Error:服务器内部错误,无法完成请求
• 502 Bad Gateway:作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
• 504 Gateway Timeout:充当网关或代理的服务器,未及时从远端服务器获取请求
• 。。。。。
看完了上述的内容,再来看一下HttpStatus这个枚举类里面的内容,它和上面的内容相对应
// 1xx Informational
CONTINUE(100, Series.INFORMATIONAL, "Continue"),
SWITCHING_PROTOCOLS(101, Series.INFORMATIONAL, "Switching Protocols"),
PROCESSING(102, Series.INFORMATIONAL, "Processing"),
CHECKPOINT(103, Series.INFORMATIONAL, "Checkpoint"),
// 2xx Success
OK(200, Series.SUCCESSFUL, "OK"),
CREATED(201, Series.SUCCESSFUL, "Created"),
ACCEPTED(202, Series.SUCCESSFUL, "Accepted"),
NON_AUTHORITATIVE_INFORMATION(203, Series.SUCCESSFUL, "Non-Authoritative Information"),
NO_CONTENT(204, Series.SUCCESSFUL, "No Content"),
RESET_CONTENT(205, Series.SUCCESSFUL, "Reset Content"),
PARTIAL_CONTENT(206, Series.SUCCESSFUL, "Partial Content"),
MULTI_STATUS(207, Series.SUCCESSFUL, "Multi-Status"),
ALREADY_REPORTED(208, Series.SUCCESSFUL, "Already Reported"),
IM_USED(226, Series.SUCCESSFUL, "IM Used"),
// 3xx Redirection
MULTIPLE_CHOICES(300, Series.REDIRECTION, "Multiple Choices"),
MOVED_PERMANENTLY(301, Series.REDIRECTION, "Moved Permanently"),
FOUND(302, Series.REDIRECTION, "Found"),
@Deprecated
MOVED_TEMPORARILY(302, Series.REDIRECTION, "Moved Temporarily"),
SEE_OTHER(303, Series.REDIRECTION, "See Other"),
NOT_MODIFIED(304, Series.REDIRECTION, "Not Modified"),
@Deprecated
USE_PROXY(305, Series.REDIRECTION, "Use Proxy"),
TEMPORARY_REDIRECT(307, Series.REDIRECTION, "Temporary Redirect"),
PERMANENT_REDIRECT(308, Series.REDIRECTION, "Permanent Redirect"),
// --- 4xx Client Error ---
BAD_REQUEST(400, Series.CLIENT_ERROR, "Bad Request"),
UNAUTHORIZED(401, Series.CLIENT_ERROR, "Unauthorized"),
PAYMENT_REQUIRED(402, Series.CLIENT_ERROR, "Payment Required"),
FORBIDDEN(403, Series.CLIENT_ERROR, "Forbidden"),
NOT_FOUND(404, Series.CLIENT_ERROR, "Not Found"),
METHOD_NOT_ALLOWED(405, Series.CLIENT_ERROR, "Method Not Allowed"),
NOT_ACCEPTABLE(406, Series.CLIENT_ERROR, "Not Acceptable"),
PROXY_AUTHENTICATION_REQUIRED(407, Series.CLIENT_ERROR, "Proxy Authentication Required"),
REQUEST_TIMEOUT(408, Series.CLIENT_ERROR, "Request Timeout"),
CONFLICT(409, Series.CLIENT_ERROR, "Conflict"),
GONE(410, Series.CLIENT_ERROR, "Gone"),
LENGTH_REQUIRED(411, Series.CLIENT_ERROR, "Length Required"),
PRECONDITION_FAILED(412, Series.CLIENT_ERROR, "Precondition Failed"),
PAYLOAD_TOO_LARGE(413, Series.CLIENT_ERROR, "Payload Too Large"),
@Deprecated
REQUEST_ENTITY_TOO_LARGE(413, Series.CLIENT_ERROR, "Request Entity Too Large"),
URI_TOO_LONG(414, Series.CLIENT_ERROR, "URI Too Long"),
@Deprecated
REQUEST_URI_TOO_LONG(414, Series.CLIENT_ERROR, "Request-URI Too Long"),
UNSUPPORTED_MEDIA_TYPE(415, Series.CLIENT_ERROR, "Unsupported Media Type"),
REQUESTED_RANGE_NOT_SATISFIABLE(416, Series.CLIENT_ERROR, "Requested range not satisfiable"),
EXPECTATION_FAILED(417, Series.CLIENT_ERROR, "Expectation Failed"),
I_AM_A_TEAPOT(418, Series.CLIENT_ERROR, "I'm a teapot"),
...
// --- 5xx Server Error ---
INTERNAL_SERVER_ERROR(500, Series.SERVER_ERROR, "Internal Server Error"),
NOT_IMPLEMENTED(501, Series.SERVER_ERROR, "Not Implemented"),
BAD_GATEWAY(502, Series.SERVER_ERROR, "Bad Gateway"),
SERVICE_UNAVAILABLE(503, Series.SERVER_ERROR, "Service Unavailable"),
GATEWAY_TIMEOUT(504, Series.SERVER_ERROR, "Gateway Timeout"),
HTTP_VERSION_NOT_SUPPORTED(505, Series.SERVER_ERROR, "HTTP Version not supported"),
VARIANT_ALSO_NEGOTIATES(506, Series.SERVER_ERROR, "Variant Also Negotiates"),
INSUFFICIENT_STORAGE(507, Series.SERVER_ERROR, "Insufficient Storage"),
LOOP_DETECTED(508, Series.SERVER_ERROR, "Loop Detected"),
BANDWIDTH_LIMIT_EXCEEDED(509, Series.SERVER_ERROR, "Bandwidth Limit Exceeded"),
NOT_EXTENDED(510, Series.SERVER_ERROR, "Not Extended"),
NETWORK_AUTHENTICATION_REQUIRED(511, Series.SERVER_ERROR, "Network Authentication Required");
是不是觉得是熟悉啊
来看看它的属性和构造函数
属性
//状态码的值
private final int value;
//序列号
private final Series series;
//错误提示
private final String reasonPhrase;
构造方法
HttpStatus(int value, Series series, String reasonPhrase) {
this.value = value;
this.series = series;
this.reasonPhrase = reasonPhrase;
}
其他方法
//返回状态码的值
public int value() {return this.value;}
public static HttpStatus valueOf(int statusCode) {...}
//返回状态码的序列号
public Series series() {return this.series;}
//返回错误信息
public String getReasonPhrase() {return this.reasonPhrase;}
//判断是否为1开头的状态码
public boolean is1xxInformational() {
return (series() == Series.INFORMATIONAL);
}
//判断是否为2开头的状态码
public boolean is2xxSuccessful() {
return (series() == Series.SUCCESSFUL);
}
。。。
接下来看看序列号
序列号
Enumeration of HTTP status series.
HTTP 状态码序列号的枚举,主要分为5类:信息、成功、重定向、客户端异常、服务器异常
public enum Series {
INFORMATIONAL(1),//临时响应
SUCCESSFUL(2),//请求成功
REDIRECTION(3),//重定向
CLIENT_ERROR(4),//客户端异常
SERVER_ERROR(5);//服务器异常
private final int value;
Series(int value) {
this.value = value;
}
/**返回状态码序列号的值
* Return the integer value of this status series. Ranges from 1 to 5.
*/
public int value() {
return this.value;
}
。。。
}
HttpStatus的内容完了
4、ResponseEntity的其他方法
//返回响应的HTTP状态码。
public HttpStatus getStatusCode() {
if (this.status instanceof HttpStatus) {
return (HttpStatus) this.status;
}
else {
return HttpStatus.valueOf((Integer) this.status);
}
}
/**
* 返回响应的HTTP状态码的值。该值是一个int值
* Return the HTTP status code of the response.
* @return the HTTP status as an int value
* @since 4.3
*/
public int getStatusCodeValue() {
if (this.status instanceof HttpStatus) {
return ((HttpStatus) this.status).value();
}
else {
return (Integer) this.status;
}
}
5、BodyBuilder和HeadersBuilder介绍
ResponseEntity中有两个接口,BodyBuilder和HeadersBuilder ,前者是给响应实体添加主体的一个构建器,后者定义将头添加到响应实体的构建器。
HeadersBuilder
//Defines a builder that adds headers to the response entity.
//定义一个将头部信息添加到响应体的构建器
public interface HeadersBuilder<B extends HeadersBuilder<B>> {
//Add the given, single header value under the given name.
//在给定的名称下添加给定的头部值。
B header(String headerName, String... headerValues);
//Copy the given headers into the entity's headers map.
B headers(@Nullable HttpHeaders headers);
B headers(Consumer<HttpHeaders> headersConsumer);
//Build the response entity with no body. 构建没有主体的响应实体。
<T> ResponseEntity<T> build();
}
}
BodyBuilder
/**
* Defines a builder that adds a body to the response entity.
* 定义了一个添加body到响应实体的构建器
* @since 4.1
*/
public interface BodyBuilder extends HeadersBuilder<BodyBuilder> {
//Set the length of the body in bytes, as specified by the Content-Length header.
//以字节为单位设置正文的长度,由Content-Length头指定。
BodyBuilder contentLength(long contentLength);
//Set the media type of the body, as specified by the Content-Type header.
//设置主体的媒体类型,由Content-Type标题指定。
BodyBuilder contentType(MediaType contentType);
//Set the body of the response entity and returns it.
//设置响应实体的主体并返回它
<T> ResponseEntity<T> body(@Nullable T body);
}
我以为已经没有builder了,没想到还有一个BodyBuilder默认的实现类
private static class DefaultBuilder implements BodyBuilder {
private final Object statusCode;//状态码
private final HttpHeaders headers = new HttpHeaders(); //头部信息
//有状态码的构造器
public DefaultBuilder(Object statusCode) {
this.statusCode = statusCode;
}
@Override
public BodyBuilder header(String headerName, String... headerValues) {
for (String headerValue : headerValues) {
this.headers.add(headerName, headerValue);
}
return this;
}
。。。。
//其他的方法都是重写接口里的
6、静态方法
// Static builder methods
/**
* 根据被给定的HttpStatus状态码创建一个构建器
* Create a builder with the given status.
* @param status the response status
* @return the created builder
* @since 4.1
*/
public static BodyBuilder status(HttpStatus status) {
Assert.notNull(status, "HttpStatus must not be null");
return new DefaultBuilder(status);
}
/**根据被给定的int类型的状态码创建一个构建器
* Create a builder with the given status.
* @param status the response status
* @return the created builder
* @since 4.1
*/
public static BodyBuilder status(int status) {
return new DefaultBuilder(status);
}
/**
* Create a builder with the status set to {@linkplain HttpStatus#OK OK}.
* 创建一个状态设置为OK的构建器。
* @return the created builder
* @since 4.1
*/
public static BodyBuilder ok() {
return status(HttpStatus.OK);
}
/** 创建具有给定主体和状态设置为OK的ResponseEntity的快捷方式。
* A shortcut for creating a {@code ResponseEntity} with the given body
* and the status set to {@linkplain HttpStatus#OK OK}.
* @param body the body of the response entity (possibly empty)
* @return the created {@code ResponseEntity}
* @since 4.1
*/
public static <T> ResponseEntity<T> ok(@Nullable T body) {
return ok().body(body);
}
/**
一个快捷方式,用于创建具有给定主体和OK状态的ResponseEntity,或者在Optional.empty()参数的情况下,创建一个空主体和NOT FOUND状态的ResponseEntity。
* A shortcut for creating a {@code ResponseEntity} with the given body
* and the {@linkplain HttpStatus#OK OK} status, or an empty body and a
* {@linkplain HttpStatus#NOT_FOUND NOT FOUND} status in case of an
* {@linkplain Optional#empty()} parameter.
* @return the created {@code ResponseEntity}
* @since 5.1
*/
public static <T> ResponseEntity<T> of(Optional<T> body) {
Assert.notNull(body, "Body must not be null");
return body.map(ResponseEntity::ok).orElseGet(() -> notFound().build());
}
/**创建一个新的构建器,其状态为CREATED,位置标头设置为给定URI。
* Create a new builder with a {@linkplain HttpStatus#CREATED CREATED} status
* and a location header set to the given URI.
* @param location the location URI
* @return the created builder
* @since 4.1
*/
public static BodyBuilder created(URI location) {
return status(HttpStatus.CREATED).location(location);
}
/**创建一个状态为ACCEPTED的构建器。
* Create a builder with an {@linkplain HttpStatus#ACCEPTED ACCEPTED} status.
* @return the created builder
* @since 4.1
*/
public static BodyBuilder accepted() {
return status(HttpStatus.ACCEPTED);
}
/**
* Create a builder with a {@linkplain HttpStatus#NO_CONTENT NO_CONTENT} status.
* @return the created builder
* @since 4.1
*/
public static HeadersBuilder<?> noContent() {
return status(HttpStatus.NO_CONTENT);
}
/**
* Create a builder with a {@linkplain HttpStatus#BAD_REQUEST BAD_REQUEST} status.
* @return the created builder
* @since 4.1
*/
public static BodyBuilder badRequest() {
return status(HttpStatus.BAD_REQUEST);
}
/**
* Create a builder with a {@linkplain HttpStatus#NOT_FOUND NOT_FOUND} status.
* @return the created builder
* @since 4.1
*/
public static HeadersBuilder<?> notFound() {
return status(HttpStatus.NOT_FOUND);
}
/**
* Create a builder with an
* {@linkplain HttpStatus#UNPROCESSABLE_ENTITY UNPROCESSABLE_ENTITY} status.
* @return the created builder
* @since 4.1.3
*/
public static BodyBuilder unprocessableEntity() {
return status(HttpStatus.UNPROCESSABLE_ENTITY);
}
/**创建一个状态为INTERNAL_SERVER_ERROR 内部服务器错误的构建器
* Create a builder with an
* {@linkplain HttpStatus#INTERNAL_SERVER_ERROR INTERNAL_SERVER_ERROR} status.
* @return the created builder
* @since 5.3.8
*/
public static BodyBuilder internalServerError() {
return status(HttpStatus.INTERNAL_SERVER_ERROR);
}