一、封装通用HttpClient,兼容Http/Https接口调用,方便业务层交互使用.
二、使用Pom文件如下:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
三、HttpClient封装诉求如下.
①、兼容Http/Https,目前采用跳过证书校验.
②、基于HttpClient连接池化以及过期、空闲连接清理.
③、各种超时时间设置以及重试策略.
④、简单易用,方便扩展和维护,减低使用配置.
⑤、其他j微服务调用可在此基础上封装XXXClient只需要一些鉴权和url参数就可以快速对接使用.
package com.boot.skywalk;
import lombok.Data;
/**
* 通用响应
*/
@Data
public class HttpResult {
/**
* 响应的状态码
*/
private int code;
/**
* 响应体
*/
private String body;
}
package com.boot.skywalk.exception;
/**
* 全局异常
*/
public class GlobalException extends RuntimeException {
public GlobalException(){
super();
}
public GlobalException(String message){
super(message);
}
public GlobalException(Throwable cause){
super(cause);
}
public GlobalException(String message,Throwable cause) {
super(message, cause);
}
}
RestClient封装如下:代码比较简单
package com.boot.skywalk;
import com.alibaba.fastjson.JSON;
import com.boot.skywalk.exception.GlobalException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* Http通用:RestClient
*/
@Slf4j
public final class RestClient {
private static final RestClient INSTANCE = new RestClient();
/**
* 建立连接时间
*/
private static final int CONNECTION_TIME = 3000;
/**
* 发送请求时间
*/
private static final int CONNECTION_REQUEST_TIME = 30000;
/**
* 读取数据时间
*/
private static final int SOCKET_TIME = 180000;
/**
* 重试次数
*/
private static final int RETRY = 3;
/**
* 请求类型:FORM表单
*/
private static final String REQUEST_TYPE_FORM = "application/x-www-form-urlencoded; charset=UTF-8";
/**
* 请求类型:JSON体
*/
private static final String REQUEST_TYPE_JSON = "application/json; charset=utf-8";
private RestClient() {
}
/**
* Http Get:不带请求参数
*
* @param url url
* @param headerMap headerMap
* @return String
*/
public String get(String url, Map<String, Object> headerMap) {
return get(url, headerMap, null);
}
/**
* Http Get:带请求参数
*
* @param url url
* @param headerMap headerMap
* @param params params
* @return String
*/
public String get(String url, Map<String, Object> headerMap, Map<String, Object> params) {
checkUrl(url);
checkHeader(headerMap);
return doGet(url, headerMap, params, StandardCharsets.UTF_8);
}
/**
* Http Post:Form表单不带请求参数
*
* @param url URL
* @param headerMap headerMap
* @return String
*/
public String post(String url, Map<String, Object> headerMap) {
return doPostForForm(url, headerMap, null, StandardCharsets.UTF_8);
}
/**
* Http Post:根据请头识别FORM表单还是JSON体
*
* @param url url
* @param map map
* @return String
*/
public String post(String url, Map<String, Object> headerMap, Map<String, Object> map) {
checkUrl(url);
checkHeader(headerMap);
checkBody(map);
String contentType = (String) headerMap.get("Content-type");
if (REQUEST_TYPE_FORM.equalsIgnoreCase(contentType)) {
return doPostForForm(url, headerMap, map, StandardCharsets.UTF_8);
} else if (REQUEST_TYPE_JSON.equalsIgnoreCase(contentType)) {
return doPostForJson(url, headerMap, map, StandardCharsets.UTF_8);
} else {
log.error("not support this post type");
throw new GlobalException("not support this post type");
}
}
/**
* HTTP Put:Form表单方式不带参数
* Content-type:application/x-www-form-urlencoded; charset=UTF-8
* @param url url
* @param headerMap headerMap
* @return String
*/
public static String put(String url, Map<String,Object> headerMap) {
checkUrl(url);
checkHeader(headerMap);
return doPut(url, headerMap, null);
}
/**
* Http Delete:不带参数的表单形式
* Content-type:application/x-www-form-urlencoded; charset=UTF-8
* @param url url
* @param headerMap header
* @return HttpResult
*/
public static String delete(String url, Map<String, Object> headerMap){
checkUrl(url);
checkHeader(headerMap);
return doDelete(url, headerMap, null);
}
/**
* HTTP Get:带请求参数
*
* @param url 请求的url地址 ?之前的地址
* @param headerMap 请求头
* @param params 请求的参数
* @param charset 编码格式
* @return String
*/
public static String doGet(String url, Map<String, Object> headerMap, Map<String, Object> params, Charset charset) {
StringBuffer resultBuffer = null;
BufferedReader bufferedReader = null;
CloseableHttpResponse response = null;
URIBuilder uriBuilder = null;
String result = null;
try {
uriBuilder = new URIBuilder(url);
if(MapUtils.isNotEmpty(params)) {
for (Map.Entry<String, Object> entry : params.entrySet()) {
uriBuilder.setParameter(entry.getKey(), entry.getValue().toString());
}
}
HttpGet httpGet = new HttpGet(uriBuilder.build());
headerMap.forEach((key, value) -> {
httpGet.addHeader(key, value.toString());
});
response = httpClient().execute(httpGet);
if (Objects.nonNull(response.getEntity())) {
result = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
}
} catch (URISyntaxException e) {
log.error("url synctax error", e);
} catch (Exception e) {
log.error("execute get request error", e);
} finally {
close(response);
}
return result;
}
/**
* HTTP Post:Form表单方式
* Content-type:application/x-www-form-urlencoded; charset=UTF-8
*
* @param url 请求的url地址?之前的地址
* @param headerMap 请求头的参数
* @param paramMap 请求的参数
* @param charset 编码格式
* @return String
*/
public static String doPostForForm(String url, Map<String, Object> headerMap, Map<String, Object> paramMap, Charset charset) {
List<NameValuePair> pairs = null;
CloseableHttpResponse response = null;
String result = null;
pairs = new ArrayList<>(paramMap.size());
for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
if (entry.getValue() != null) {
pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
}
}
HttpPost httpPost = new HttpPost(url);
headerMap.forEach((key, value) -> {
httpPost.setHeader(key, value.toString());
});
if (CollectionUtils.isNotEmpty(pairs)) {
httpPost.setEntity(new UrlEncodedFormEntity(pairs, charset));
}
try {
response = httpClient().execute(httpPost);
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity, charset);
}
} catch (Exception e) {
log.error("execute post request error", e);
} finally {
close(response);
}
return result;
}
/**
* HTTP Post:JSON形式
* Content-type:application/json; charset=utf-8
*
* @param url 请求的url地址?之前的地址
* @param headerMap 请求头的参数
* @param bodyMap 请求的参数
* @param charset 编码格式
* @return String
*/
public static String doPostForJson(String url, Map<String, Object> headerMap, Map<String, Object> bodyMap, Charset charset) {
CloseableHttpResponse response = null;
String result = null;
HttpPost httpPost = new HttpPost(url);
// Body参数设置到请求体中
httpPost.setEntity(new StringEntity(JSON.toJSONString(bodyMap), charset));
headerMap.forEach((key, value) -> {
httpPost.setHeader(key, value.toString());
});
try {
response = httpClient().execute(httpPost);
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity, charset);
}
} catch (Exception e) {
log.error("execute post request error", e);
} finally {
close(response);
}
return result;
}
/**
* HTTP Put:Form表单方式带参数
* Content-type:application/x-www-form-urlencoded; charset=UTF-8
*
* @param url url
* @param headerMap headerMap
* @param paramMap paramMap
* @return String
*/
public static String doPut(String url, Map<String, Object> headerMap, Map<String, Object> paramMap) {
HttpPut httpPut = new HttpPut(url);
String result = null;
CloseableHttpResponse response = null;
List<NameValuePair> parameters = new ArrayList<>();
if (MapUtils.isNotEmpty(paramMap)) {
for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
}
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8);
httpPut.setEntity(entity);
headerMap.forEach((key, value) -> {
httpPut.setHeader(key, value.toString());
});
try {
response = httpClient().execute(httpPut);
int code = response.getStatusLine().getStatusCode();
if (response.getEntity() != null) {
result = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
}
} catch (IOException e) {
log.error("io error", e);
} catch (Exception e) {
log.error("execute put request error", e);
} finally {
close(response);
}
return result;
}
/**
* Http Delete:不带参数的表单形式
* Content-type:application/x-www-form-urlencoded; charset=UTF-8
* @param url url
* @param headerMap headerMap
* @param paramMap paramMap
* @return String
*/
public static String doDelete(String url, Map<String, Object> headerMap, Map<String, Object> paramMap) {
URIBuilder uriBuilder = null;
String result = null;
CloseableHttpResponse response = null;
try {
uriBuilder = new URIBuilder(url);
if (MapUtils.isNotEmpty(paramMap)) {
for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
uriBuilder.setParameter(entry.getKey(), entry.getValue().toString());
}
}
HttpDelete httpDelete = new HttpDelete(uriBuilder.build());
headerMap.forEach((key, value) -> {
httpDelete.setHeader(key, value.toString());
});
response = httpClient().execute(httpDelete);
int code = response.getStatusLine().getStatusCode();
if (Objects.nonNull(response.getEntity())) {
result = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
}
} catch (URISyntaxException e) {
log.error("url synctax error", e);
} catch (Exception e) {
log.error("execute post request error", e);
} finally {
close(response);
}
return result;
}
public static RestClient getInstance() {
return INSTANCE;
}
/**
* 忽略证书验证的CloseableHttpClient对象,适配Http/Https
*
* @return CloseableHttpClient
*/
public static CloseableHttpClient httpClient() {
CloseableHttpClient closeableHttpClient = null;
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, getTrustingManager(), new java.security.SecureRandom());
// 使用上面的策略初始化上下文
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sc,
new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE);
closeableHttpClient = HttpClients.custom()
// 设置超时时间
.setDefaultRequestConfig(getRequestConfig())
// 设置连接池
.setConnectionManager(getPoolingManager())
// 设置重试策略,框架层面重试,可以在业务层面重试
//.setRetryHandler(getRetryHandler())
.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
// 连接池清理过期连接
.evictExpiredConnections()
// 连接池释放空闲连接
.evictIdleConnections(60, TimeUnit.SECONDS)
.build();
} catch (KeyManagementException e) {
log.error("KeyManagement error", e);
} catch (NoSuchAlgorithmException e) {
log.error("No Such Algorithm error", e);
}
return closeableHttpClient;
}
/**
* 信任所有证书
*
* @return TrustManager[]
*/
private static TrustManager[] getTrustingManager() {
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
}};
return trustAllCerts;
}
/**
* Http连接池配置
*
* @return HttpClientConnectionManager
*/
public static HttpClientConnectionManager getPoolingManager() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
SSLContext.setDefault(sslContext);
Registry<ConnectionSocketFactory> socketFactoryRegistry =
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sslContext)).build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
// 设置整个连接池最大连接数
connectionManager.setMaxTotal(200);
// 最大路由
connectionManager.setDefaultMaxPerRoute(10);
return connectionManager;
}
/**
* 封装RequestConfig
*
* @return RequestConfig
*/
public static RequestConfig getRequestConfig() {
RequestConfig requestConfig = RequestConfig.custom().
setConnectTimeout(getConnectionTime()).
setConnectionRequestTimeout(getConnectionRequestTime())
.setSocketTimeout(getSocketTime()).build();
return requestConfig;
}
/**
* HttpClient的重试策略
*
* @return HttpRequestRetryHandler
*/
public static HttpRequestRetryHandler getRetryHandler() {
HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(
IOException exception,
int executionCount,
HttpContext context) {
// 重试三次
if (executionCount >= RETRY) {
return false;
}
if (exception instanceof InterruptedIOException) {
// 超时
return false;
}
if (exception instanceof UnknownHostException) {
// 目标服务器不可达
return false;
}
if (exception instanceof ConnectTimeoutException) {
// 连接被拒绝
return false;
}
if (exception instanceof SSLException) {
// SSL握手异常
return false;
}
HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
// 如果请求是幂等的,就再次尝试
return true;
}
return false;
}
};
return retryHandler;
}
public static Integer getConnectionTime() {
return CONNECTION_TIME;
}
public static Integer getConnectionRequestTime() {
return CONNECTION_REQUEST_TIME;
}
public static Integer getSocketTime() {
return SOCKET_TIME;
}
/**
* 校验url,支持扩展
*
* @param url
*/
private static void checkUrl(String url) {
if (StringUtils.isBlank(url)) {
log.error("rest client request url not null");
throw new GlobalException("rest client request url not null");
}
}
/**
* 校验Header,支持扩展
*
* @param headerMap
*/
private static void checkHeader(Map<String, Object> headerMap) {
if (MapUtils.isEmpty(headerMap)) {
log.error("rest client request header not null");
throw new GlobalException("rest client request header not null");
}
}
/**
* 校验Body,支持扩展
*
* @param bodyMap
*/
private static void checkBody(Map<String, Object> bodyMap) {
if (MapUtils.isEmpty(bodyMap)) {
log.error("rest client request param map not null");
throw new GlobalException("rest client request map not null");
}
}
/**
* 关闭流资源
*
* @param closeable
*/
private static void close(Closeable closeable) {
try {
closeable.close();
} catch (IOException e) {
log.error("close error", e);
}
}
四、测试请求
①、Http+Get无参数
String url="http://test.code.com/skywalk/test/log/filter";
Map<String, Object> headerMap = new HashMap<>();
headerMap.put("Content-type", "application/json; charset=utf-8");
headerMap.put("Accept", "application/json");
String string = RestClient.getInstance().get(url, headerMap);
System.out.println(string);
②、Https接口+Post表单
这里调用阿里云接口手机号码+IP归属地Https接口为例【云厂商目前都提供一些免费的Https接口供测试使用的,非常方便,这里使用AppCode鉴权】
String url = "https://jmipquery3.market.alicloudapi.com/ip/query-v3/";
Map<String, Object> headerMap = new HashMap<>();
headerMap.put("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
headerMap.put("Accept", "application/json");
headerMap.put("Authorization", "APPCODE 你的code");
Map<String, Object> bodyMap = new HashMap<>();
bodyMap.put("ip", "117.173.222.90");
String string = RestClient.getInstance().post(url, headerMap, bodyMap);
System.out.println(string);
③、Https接口+Get带参数
String url = "https://api04.aliyun.venuscn.com/mobile";
Map<String, Object> headerMap = new HashMap<>();
Map<String, Object> bodyMap = new HashMap<>();
headerMap.put("Content-type", "text/html; charset=utf-8");
headerMap.put("Accept", "application/json");
headerMap.put("Authorization", "APPCODE 你的code");
bodyMap.put("mobile", "18138434699");
关于重试说明:
①、不重试写法:
setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
②、默认是重试三次
public DefaultHttpRequestRetryHandler() {
this(3, false);
}
③、自定义重试策略,哪些异常需要,哪些异常不需要.
public static HttpRequestRetryHandler getRetryHandler() {
HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(
IOException exception,
int executionCount,
HttpContext context) {
// 重试三次
if (executionCount >= RETRY) {
return false;
}
if (exception instanceof InterruptedIOException) {
// 超时
return false;
}
if (exception instanceof UnknownHostException) {
// 目标服务器不可达
return false;
}
if (exception instanceof ConnectTimeoutException) {
// 连接被拒绝
return false;
}
if (exception instanceof SSLException) {
// SSL握手异常
return false;
}
HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
// 如果请求是幂等的,就再次尝试
return true;
}
return false;
}
};
return retryHandler;
}
④、业务层调用可以使用函数式接口或者while循环重试调用三次.
更多业务参数参考这篇博客:HttpClient专题
【附录HttpStatus】
①、Apache下HttpClient的HttpStatus。
package org.apache.http;
/**
* Constants enumerating the HTTP status codes.
* All status codes defined in RFC1945 (HTTP/1.0), RFC2616 (HTTP/1.1), and
* RFC2518 (WebDAV) are listed.
*
* @see StatusLine
* @see <a href="https://tools.ietf.org/html/rfc1945">RFC1945 (HTTP/1.0)</a>
* @see <a href="https://tools.ietf.org/html/rfc2616">RFC2616 (HTTP/1.1)</a>
* @see <a href="https://tools.ietf.org/html/rfc2518">RFC2518 (WebDAV)</a>
* @since 4.0
*/
public interface HttpStatus {
// --- 1xx Informational ---
/** {@code 100 Continue} (HTTP/1.1 - RFC 2616) */
int SC_CONTINUE = 100;
/** {@code 101 Switching Protocols} (HTTP/1.1 - RFC 2616)*/
int SC_SWITCHING_PROTOCOLS = 101;
/** {@code 102 Processing} (WebDAV - RFC 2518) */
int SC_PROCESSING = 102;
// --- 2xx Success ---
/** {@code 200 OK} (HTTP/1.0 - RFC 1945) */
int SC_OK = 200;
/** {@code 201 Created} (HTTP/1.0 - RFC 1945) */
int SC_CREATED = 201;
/** {@code 202 Accepted} (HTTP/1.0 - RFC 1945) */
int SC_ACCEPTED = 202;
/** {@code 203 Non Authoritative Information} (HTTP/1.1 - RFC 2616) */
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
/** {@code 204 No Content} (HTTP/1.0 - RFC 1945) */
int SC_NO_CONTENT = 204;
/** {@code 205 Reset Content} (HTTP/1.1 - RFC 2616) */
int SC_RESET_CONTENT = 205;
/** {@code 206 Partial Content} (HTTP/1.1 - RFC 2616) */
int SC_PARTIAL_CONTENT = 206;
/**
* {@code 207 Multi-Status} (WebDAV - RFC 2518)
* or
* {@code 207 Partial Update OK} (HTTP/1.1 - draft-ietf-http-v11-spec-rev-01?)
*/
int SC_MULTI_STATUS = 207;
// --- 3xx Redirection ---
/** {@code 300 Mutliple Choices} (HTTP/1.1 - RFC 2616) */
int SC_MULTIPLE_CHOICES = 300;
/** {@code 301 Moved Permanently} (HTTP/1.0 - RFC 1945) */
int SC_MOVED_PERMANENTLY = 301;
/** {@code 302 Moved Temporarily} (Sometimes {@code Found}) (HTTP/1.0 - RFC 1945) */
int SC_MOVED_TEMPORARILY = 302;
/** {@code 303 See Other} (HTTP/1.1 - RFC 2616) */
int SC_SEE_OTHER = 303;
/** {@code 304 Not Modified} (HTTP/1.0 - RFC 1945) */
int SC_NOT_MODIFIED = 304;
/** {@code 305 Use Proxy} (HTTP/1.1 - RFC 2616) */
int SC_USE_PROXY = 305;
/** {@code 307 Temporary Redirect} (HTTP/1.1 - RFC 2616) */
int SC_TEMPORARY_REDIRECT = 307;
// --- 4xx Client Error ---
/** {@code 400 Bad Request} (HTTP/1.1 - RFC 2616) */
int SC_BAD_REQUEST = 400;
/** {@code 401 Unauthorized} (HTTP/1.0 - RFC 1945) */
int SC_UNAUTHORIZED = 401;
/** {@code 402 Payment Required} (HTTP/1.1 - RFC 2616) */
int SC_PAYMENT_REQUIRED = 402;
/** {@code 403 Forbidden} (HTTP/1.0 - RFC 1945) */
int SC_FORBIDDEN = 403;
/** {@code 404 Not Found} (HTTP/1.0 - RFC 1945) */
int SC_NOT_FOUND = 404;
/** {@code 405 Method Not Allowed} (HTTP/1.1 - RFC 2616) */
int SC_METHOD_NOT_ALLOWED = 405;
/** {@code 406 Not Acceptable} (HTTP/1.1 - RFC 2616) */
int SC_NOT_ACCEPTABLE = 406;
/** {@code 407 Proxy Authentication Required} (HTTP/1.1 - RFC 2616)*/
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
/** {@code 408 Request Timeout} (HTTP/1.1 - RFC 2616) */
int SC_REQUEST_TIMEOUT = 408;
/** {@code 409 Conflict} (HTTP/1.1 - RFC 2616) */
int SC_CONFLICT = 409;
/** {@code 410 Gone} (HTTP/1.1 - RFC 2616) */
int SC_GONE = 410;
/** {@code 411 Length Required} (HTTP/1.1 - RFC 2616) */
int SC_LENGTH_REQUIRED = 411;
/** {@code 412 Precondition Failed} (HTTP/1.1 - RFC 2616) */
int SC_PRECONDITION_FAILED = 412;
/** {@code 413 Request Entity Too Large} (HTTP/1.1 - RFC 2616) */
int SC_REQUEST_TOO_LONG = 413;
/** {@code 414 Request-URI Too Long} (HTTP/1.1 - RFC 2616) */
int SC_REQUEST_URI_TOO_LONG = 414;
/** {@code 415 Unsupported Media Type} (HTTP/1.1 - RFC 2616) */
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
/** {@code 416 Requested Range Not Satisfiable} (HTTP/1.1 - RFC 2616) */
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
/** {@code 417 Expectation Failed} (HTTP/1.1 - RFC 2616) */
int SC_EXPECTATION_FAILED = 417;
/**
* Static constant for a 418 error.
* {@code 418 Unprocessable Entity} (WebDAV drafts?)
* or {@code 418 Reauthentication Required} (HTTP/1.1 drafts?)
*/
// not used
// public static final int SC_UNPROCESSABLE_ENTITY = 418;
/**
* Static constant for a 419 error.
* {@code 419 Insufficient Space on Resource}
* (WebDAV - draft-ietf-webdav-protocol-05?)
* or {@code 419 Proxy Reauthentication Required}
* (HTTP/1.1 drafts?)
*/
int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419;
/**
* Static constant for a 420 error.
* {@code 420 Method Failure}
* (WebDAV - draft-ietf-webdav-protocol-05?)
*/
int SC_METHOD_FAILURE = 420;
/** {@code 422 Unprocessable Entity} (WebDAV - RFC 2518) */
int SC_UNPROCESSABLE_ENTITY = 422;
/** {@code 423 Locked} (WebDAV - RFC 2518) */
int SC_LOCKED = 423;
/** {@code 424 Failed Dependency} (WebDAV - RFC 2518) */
int SC_FAILED_DEPENDENCY = 424;
/** {@code 429 Too Many Requests} (Additional HTTP Status Codes - RFC 6585) */
int SC_TOO_MANY_REQUESTS = 429;
// --- 5xx Server Error ---
/** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */
int SC_INTERNAL_SERVER_ERROR = 500;
/** {@code 501 Not Implemented} (HTTP/1.0 - RFC 1945) */
int SC_NOT_IMPLEMENTED = 501;
/** {@code 502 Bad Gateway} (HTTP/1.0 - RFC 1945) */
int SC_BAD_GATEWAY = 502;
/** {@code 503 Service Unavailable} (HTTP/1.0 - RFC 1945) */
int SC_SERVICE_UNAVAILABLE = 503;
/** {@code 504 Gateway Timeout} (HTTP/1.1 - RFC 2616) */
int SC_GATEWAY_TIMEOUT = 504;
/** {@code 505 HTTP Version Not Supported} (HTTP/1.1 - RFC 2616) */
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
/** {@code 507 Insufficient Storage} (WebDAV - RFC 2518) */
int SC_INSUFFICIENT_STORAGE = 507;
}
②、Spring框架的HttpStatus。
package org.springframework.http;
import org.springframework.lang.Nullable;
/**
* Enumeration of HTTP status codes.
*
* <p>The HTTP status code series can be retrieved via {@link #series()}.
*
* @author Arjen Poutsma
* @author Sebastien Deleuze
* @author Brian Clozel
* @since 3.0
* @see HttpStatus.Series
* @see <a href="https://www.iana.org/assignments/http-status-codes">HTTP Status Code Registry</a>
* @see <a href="https://en.wikipedia.org/wiki/List_of_HTTP_status_codes">List of HTTP status codes - Wikipedia</a>
*/
public enum HttpStatus {
// 1xx Informational
/**
* {@code 100 Continue}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.2.1">HTTP/1.1: Semantics and Content, section 6.2.1</a>
*/
CONTINUE(100, Series.INFORMATIONAL, "Continue"),
/**
* {@code 101 Switching Protocols}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.2.2">HTTP/1.1: Semantics and Content, section 6.2.2</a>
*/
SWITCHING_PROTOCOLS(101, Series.INFORMATIONAL, "Switching Protocols"),
/**
* {@code 102 Processing}.
* @see <a href="https://tools.ietf.org/html/rfc2518#section-10.1">WebDAV</a>
*/
PROCESSING(102, Series.INFORMATIONAL, "Processing"),
/**
* {@code 103 Checkpoint}.
* @see <a href="https://code.google.com/p/gears/wiki/ResumableHttpRequestsProposal">A proposal for supporting
* resumable POST/PUT HTTP requests in HTTP/1.0</a>
*/
CHECKPOINT(103, Series.INFORMATIONAL, "Checkpoint"),
// 2xx Success
/**
* {@code 200 OK}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.3.1">HTTP/1.1: Semantics and Content, section 6.3.1</a>
*/
OK(200, Series.SUCCESSFUL, "OK"),
/**
* {@code 201 Created}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.3.2">HTTP/1.1: Semantics and Content, section 6.3.2</a>
*/
CREATED(201, Series.SUCCESSFUL, "Created"),
/**
* {@code 202 Accepted}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.3.3">HTTP/1.1: Semantics and Content, section 6.3.3</a>
*/
ACCEPTED(202, Series.SUCCESSFUL, "Accepted"),
/**
* {@code 203 Non-Authoritative Information}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.3.4">HTTP/1.1: Semantics and Content, section 6.3.4</a>
*/
NON_AUTHORITATIVE_INFORMATION(203, Series.SUCCESSFUL, "Non-Authoritative Information"),
/**
* {@code 204 No Content}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.3.5">HTTP/1.1: Semantics and Content, section 6.3.5</a>
*/
NO_CONTENT(204, Series.SUCCESSFUL, "No Content"),
/**
* {@code 205 Reset Content}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.3.6">HTTP/1.1: Semantics and Content, section 6.3.6</a>
*/
RESET_CONTENT(205, Series.SUCCESSFUL, "Reset Content"),
/**
* {@code 206 Partial Content}.
* @see <a href="https://tools.ietf.org/html/rfc7233#section-4.1">HTTP/1.1: Range Requests, section 4.1</a>
*/
PARTIAL_CONTENT(206, Series.SUCCESSFUL, "Partial Content"),
/**
* {@code 207 Multi-Status}.
* @see <a href="https://tools.ietf.org/html/rfc4918#section-13">WebDAV</a>
*/
MULTI_STATUS(207, Series.SUCCESSFUL, "Multi-Status"),
/**
* {@code 208 Already Reported}.
* @see <a href="https://tools.ietf.org/html/rfc5842#section-7.1">WebDAV Binding Extensions</a>
*/
ALREADY_REPORTED(208, Series.SUCCESSFUL, "Already Reported"),
/**
* {@code 226 IM Used}.
* @see <a href="https://tools.ietf.org/html/rfc3229#section-10.4.1">Delta encoding in HTTP</a>
*/
IM_USED(226, Series.SUCCESSFUL, "IM Used"),
// 3xx Redirection
/**
* {@code 300 Multiple Choices}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.4.1">HTTP/1.1: Semantics and Content, section 6.4.1</a>
*/
MULTIPLE_CHOICES(300, Series.REDIRECTION, "Multiple Choices"),
/**
* {@code 301 Moved Permanently}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.4.2">HTTP/1.1: Semantics and Content, section 6.4.2</a>
*/
MOVED_PERMANENTLY(301, Series.REDIRECTION, "Moved Permanently"),
/**
* {@code 302 Found}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.4.3">HTTP/1.1: Semantics and Content, section 6.4.3</a>
*/
FOUND(302, Series.REDIRECTION, "Found"),
/**
* {@code 302 Moved Temporarily}.
* @see <a href="https://tools.ietf.org/html/rfc1945#section-9.3">HTTP/1.0, section 9.3</a>
* @deprecated in favor of {@link #FOUND} which will be returned from {@code HttpStatus.valueOf(302)}
*/
@Deprecated
MOVED_TEMPORARILY(302, Series.REDIRECTION, "Moved Temporarily"),
/**
* {@code 303 See Other}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.4.4">HTTP/1.1: Semantics and Content, section 6.4.4</a>
*/
SEE_OTHER(303, Series.REDIRECTION, "See Other"),
/**
* {@code 304 Not Modified}.
* @see <a href="https://tools.ietf.org/html/rfc7232#section-4.1">HTTP/1.1: Conditional Requests, section 4.1</a>
*/
NOT_MODIFIED(304, Series.REDIRECTION, "Not Modified"),
/**
* {@code 305 Use Proxy}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.4.5">HTTP/1.1: Semantics and Content, section 6.4.5</a>
* @deprecated due to security concerns regarding in-band configuration of a proxy
*/
@Deprecated
USE_PROXY(305, Series.REDIRECTION, "Use Proxy"),
/**
* {@code 307 Temporary Redirect}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.4.7">HTTP/1.1: Semantics and Content, section 6.4.7</a>
*/
TEMPORARY_REDIRECT(307, Series.REDIRECTION, "Temporary Redirect"),
/**
* {@code 308 Permanent Redirect}.
* @see <a href="https://tools.ietf.org/html/rfc7238">RFC 7238</a>
*/
PERMANENT_REDIRECT(308, Series.REDIRECTION, "Permanent Redirect"),
// --- 4xx Client Error ---
/**
* {@code 400 Bad Request}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.1">HTTP/1.1: Semantics and Content, section 6.5.1</a>
*/
BAD_REQUEST(400, Series.CLIENT_ERROR, "Bad Request"),
/**
* {@code 401 Unauthorized}.
* @see <a href="https://tools.ietf.org/html/rfc7235#section-3.1">HTTP/1.1: Authentication, section 3.1</a>
*/
UNAUTHORIZED(401, Series.CLIENT_ERROR, "Unauthorized"),
/**
* {@code 402 Payment Required}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.2">HTTP/1.1: Semantics and Content, section 6.5.2</a>
*/
PAYMENT_REQUIRED(402, Series.CLIENT_ERROR, "Payment Required"),
/**
* {@code 403 Forbidden}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.3">HTTP/1.1: Semantics and Content, section 6.5.3</a>
*/
FORBIDDEN(403, Series.CLIENT_ERROR, "Forbidden"),
/**
* {@code 404 Not Found}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.4">HTTP/1.1: Semantics and Content, section 6.5.4</a>
*/
NOT_FOUND(404, Series.CLIENT_ERROR, "Not Found"),
/**
* {@code 405 Method Not Allowed}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.5">HTTP/1.1: Semantics and Content, section 6.5.5</a>
*/
METHOD_NOT_ALLOWED(405, Series.CLIENT_ERROR, "Method Not Allowed"),
/**
* {@code 406 Not Acceptable}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.6">HTTP/1.1: Semantics and Content, section 6.5.6</a>
*/
NOT_ACCEPTABLE(406, Series.CLIENT_ERROR, "Not Acceptable"),
/**
* {@code 407 Proxy Authentication Required}.
* @see <a href="https://tools.ietf.org/html/rfc7235#section-3.2">HTTP/1.1: Authentication, section 3.2</a>
*/
PROXY_AUTHENTICATION_REQUIRED(407, Series.CLIENT_ERROR, "Proxy Authentication Required"),
/**
* {@code 408 Request Timeout}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.7">HTTP/1.1: Semantics and Content, section 6.5.7</a>
*/
REQUEST_TIMEOUT(408, Series.CLIENT_ERROR, "Request Timeout"),
/**
* {@code 409 Conflict}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.8">HTTP/1.1: Semantics and Content, section 6.5.8</a>
*/
CONFLICT(409, Series.CLIENT_ERROR, "Conflict"),
/**
* {@code 410 Gone}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.9">
* HTTP/1.1: Semantics and Content, section 6.5.9</a>
*/
GONE(410, Series.CLIENT_ERROR, "Gone"),
/**
* {@code 411 Length Required}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.10">
* HTTP/1.1: Semantics and Content, section 6.5.10</a>
*/
LENGTH_REQUIRED(411, Series.CLIENT_ERROR, "Length Required"),
/**
* {@code 412 Precondition failed}.
* @see <a href="https://tools.ietf.org/html/rfc7232#section-4.2">
* HTTP/1.1: Conditional Requests, section 4.2</a>
*/
PRECONDITION_FAILED(412, Series.CLIENT_ERROR, "Precondition Failed"),
/**
* {@code 413 Payload Too Large}.
* @since 4.1
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.11">
* HTTP/1.1: Semantics and Content, section 6.5.11</a>
*/
PAYLOAD_TOO_LARGE(413, Series.CLIENT_ERROR, "Payload Too Large"),
/**
* {@code 413 Request Entity Too Large}.
* @see <a href="https://tools.ietf.org/html/rfc2616#section-10.4.14">HTTP/1.1, section 10.4.14</a>
* @deprecated in favor of {@link #PAYLOAD_TOO_LARGE} which will be
* returned from {@code HttpStatus.valueOf(413)}
*/
@Deprecated
REQUEST_ENTITY_TOO_LARGE(413, Series.CLIENT_ERROR, "Request Entity Too Large"),
/**
* {@code 414 URI Too Long}.
* @since 4.1
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.12">
* HTTP/1.1: Semantics and Content, section 6.5.12</a>
*/
URI_TOO_LONG(414, Series.CLIENT_ERROR, "URI Too Long"),
/**
* {@code 414 Request-URI Too Long}.
* @see <a href="https://tools.ietf.org/html/rfc2616#section-10.4.15">HTTP/1.1, section 10.4.15</a>
* @deprecated in favor of {@link #URI_TOO_LONG} which will be returned from {@code HttpStatus.valueOf(414)}
*/
@Deprecated
REQUEST_URI_TOO_LONG(414, Series.CLIENT_ERROR, "Request-URI Too Long"),
/**
* {@code 415 Unsupported Media Type}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.13">
* HTTP/1.1: Semantics and Content, section 6.5.13</a>
*/
UNSUPPORTED_MEDIA_TYPE(415, Series.CLIENT_ERROR, "Unsupported Media Type"),
/**
* {@code 416 Requested Range Not Satisfiable}.
* @see <a href="https://tools.ietf.org/html/rfc7233#section-4.4">HTTP/1.1: Range Requests, section 4.4</a>
*/
REQUESTED_RANGE_NOT_SATISFIABLE(416, Series.CLIENT_ERROR, "Requested range not satisfiable"),
/**
* {@code 417 Expectation Failed}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.5.14">
* HTTP/1.1: Semantics and Content, section 6.5.14</a>
*/
EXPECTATION_FAILED(417, Series.CLIENT_ERROR, "Expectation Failed"),
/**
* {@code 418 I'm a teapot}.
* @see <a href="https://tools.ietf.org/html/rfc2324#section-2.3.2">HTCPCP/1.0</a>
*/
I_AM_A_TEAPOT(418, Series.CLIENT_ERROR, "I'm a teapot"),
/**
* @deprecated See
* <a href="https://tools.ietf.org/rfcdiff?difftype=--hwdiff&url2=draft-ietf-webdav-protocol-06.txt">
* WebDAV Draft Changes</a>
*/
@Deprecated
INSUFFICIENT_SPACE_ON_RESOURCE(419, Series.CLIENT_ERROR, "Insufficient Space On Resource"),
/**
* @deprecated See
* <a href="https://tools.ietf.org/rfcdiff?difftype=--hwdiff&url2=draft-ietf-webdav-protocol-06.txt">
* WebDAV Draft Changes</a>
*/
@Deprecated
METHOD_FAILURE(420, Series.CLIENT_ERROR, "Method Failure"),
/**
* @deprecated
* See <a href="https://tools.ietf.org/rfcdiff?difftype=--hwdiff&url2=draft-ietf-webdav-protocol-06.txt">
* WebDAV Draft Changes</a>
*/
@Deprecated
DESTINATION_LOCKED(421, Series.CLIENT_ERROR, "Destination Locked"),
/**
* {@code 422 Unprocessable Entity}.
* @see <a href="https://tools.ietf.org/html/rfc4918#section-11.2">WebDAV</a>
*/
UNPROCESSABLE_ENTITY(422, Series.CLIENT_ERROR, "Unprocessable Entity"),
/**
* {@code 423 Locked}.
* @see <a href="https://tools.ietf.org/html/rfc4918#section-11.3">WebDAV</a>
*/
LOCKED(423, Series.CLIENT_ERROR, "Locked"),
/**
* {@code 424 Failed Dependency}.
* @see <a href="https://tools.ietf.org/html/rfc4918#section-11.4">WebDAV</a>
*/
FAILED_DEPENDENCY(424, Series.CLIENT_ERROR, "Failed Dependency"),
/**
* {@code 425 Too Early}.
* @since 5.2
* @see <a href="https://tools.ietf.org/html/rfc8470">RFC 8470</a>
*/
TOO_EARLY(425, Series.CLIENT_ERROR, "Too Early"),
/**
* {@code 426 Upgrade Required}.
* @see <a href="https://tools.ietf.org/html/rfc2817#section-6">Upgrading to TLS Within HTTP/1.1</a>
*/
UPGRADE_REQUIRED(426, Series.CLIENT_ERROR, "Upgrade Required"),
/**
* {@code 428 Precondition Required}.
* @see <a href="https://tools.ietf.org/html/rfc6585#section-3">Additional HTTP Status Codes</a>
*/
PRECONDITION_REQUIRED(428, Series.CLIENT_ERROR, "Precondition Required"),
/**
* {@code 429 Too Many Requests}.
* @see <a href="https://tools.ietf.org/html/rfc6585#section-4">Additional HTTP Status Codes</a>
*/
TOO_MANY_REQUESTS(429, Series.CLIENT_ERROR, "Too Many Requests"),
/**
* {@code 431 Request Header Fields Too Large}.
* @see <a href="https://tools.ietf.org/html/rfc6585#section-5">Additional HTTP Status Codes</a>
*/
REQUEST_HEADER_FIELDS_TOO_LARGE(431, Series.CLIENT_ERROR, "Request Header Fields Too Large"),
/**
* {@code 451 Unavailable For Legal Reasons}.
* @see <a href="https://tools.ietf.org/html/draft-ietf-httpbis-legally-restricted-status-04">
* An HTTP Status Code to Report Legal Obstacles</a>
* @since 4.3
*/
UNAVAILABLE_FOR_LEGAL_REASONS(451, Series.CLIENT_ERROR, "Unavailable For Legal Reasons"),
// --- 5xx Server Error ---
/**
* {@code 500 Internal Server Error}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.6.1">HTTP/1.1: Semantics and Content, section 6.6.1</a>
*/
INTERNAL_SERVER_ERROR(500, Series.SERVER_ERROR, "Internal Server Error"),
/**
* {@code 501 Not Implemented}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.6.2">HTTP/1.1: Semantics and Content, section 6.6.2</a>
*/
NOT_IMPLEMENTED(501, Series.SERVER_ERROR, "Not Implemented"),
/**
* {@code 502 Bad Gateway}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.6.3">HTTP/1.1: Semantics and Content, section 6.6.3</a>
*/
BAD_GATEWAY(502, Series.SERVER_ERROR, "Bad Gateway"),
/**
* {@code 503 Service Unavailable}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.6.4">HTTP/1.1: Semantics and Content, section 6.6.4</a>
*/
SERVICE_UNAVAILABLE(503, Series.SERVER_ERROR, "Service Unavailable"),
/**
* {@code 504 Gateway Timeout}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.6.5">HTTP/1.1: Semantics and Content, section 6.6.5</a>
*/
GATEWAY_TIMEOUT(504, Series.SERVER_ERROR, "Gateway Timeout"),
/**
* {@code 505 HTTP Version Not Supported}.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-6.6.6">HTTP/1.1: Semantics and Content, section 6.6.6</a>
*/
HTTP_VERSION_NOT_SUPPORTED(505, Series.SERVER_ERROR, "HTTP Version not supported"),
/**
* {@code 506 Variant Also Negotiates}
* @see <a href="https://tools.ietf.org/html/rfc2295#section-8.1">Transparent Content Negotiation</a>
*/
VARIANT_ALSO_NEGOTIATES(506, Series.SERVER_ERROR, "Variant Also Negotiates"),
/**
* {@code 507 Insufficient Storage}
* @see <a href="https://tools.ietf.org/html/rfc4918#section-11.5">WebDAV</a>
*/
INSUFFICIENT_STORAGE(507, Series.SERVER_ERROR, "Insufficient Storage"),
/**
* {@code 508 Loop Detected}
* @see <a href="https://tools.ietf.org/html/rfc5842#section-7.2">WebDAV Binding Extensions</a>
*/
LOOP_DETECTED(508, Series.SERVER_ERROR, "Loop Detected"),
/**
* {@code 509 Bandwidth Limit Exceeded}
*/
BANDWIDTH_LIMIT_EXCEEDED(509, Series.SERVER_ERROR, "Bandwidth Limit Exceeded"),
/**
* {@code 510 Not Extended}
* @see <a href="https://tools.ietf.org/html/rfc2774#section-7">HTTP Extension Framework</a>
*/
NOT_EXTENDED(510, Series.SERVER_ERROR, "Not Extended"),
/**
* {@code 511 Network Authentication Required}.
* @see <a href="https://tools.ietf.org/html/rfc6585#section-6">Additional HTTP Status Codes</a>
*/
NETWORK_AUTHENTICATION_REQUIRED(511, Series.SERVER_ERROR, "Network Authentication Required");
private static final HttpStatus[] VALUES;
static {
VALUES = values();
}
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;
}
/**
* Return the integer value of this status code.
*/
public int value() {
return this.value;
}
/**
* Return the HTTP status series of this status code.
* @see HttpStatus.Series
*/
public Series series() {
return this.series;
}
/**
* Return the reason phrase of this status code.
*/
public String getReasonPhrase() {
return this.reasonPhrase;
}
/**
* Whether this status code is in the HTTP series
* {@link org.springframework.http.HttpStatus.Series#INFORMATIONAL}.
* <p>This is a shortcut for checking the value of {@link #series()}.
* @since 4.0
* @see #series()
*/
public boolean is1xxInformational() {
return (series() == Series.INFORMATIONAL);
}
/**
* Whether this status code is in the HTTP series
* {@link org.springframework.http.HttpStatus.Series#SUCCESSFUL}.
* <p>This is a shortcut for checking the value of {@link #series()}.
* @since 4.0
* @see #series()
*/
public boolean is2xxSuccessful() {
return (series() == Series.SUCCESSFUL);
}
/**
* Whether this status code is in the HTTP series
* {@link org.springframework.http.HttpStatus.Series#REDIRECTION}.
* <p>This is a shortcut for checking the value of {@link #series()}.
* @since 4.0
* @see #series()
*/
public boolean is3xxRedirection() {
return (series() == Series.REDIRECTION);
}
/**
* Whether this status code is in the HTTP series
* {@link org.springframework.http.HttpStatus.Series#CLIENT_ERROR}.
* <p>This is a shortcut for checking the value of {@link #series()}.
* @since 4.0
* @see #series()
*/
public boolean is4xxClientError() {
return (series() == Series.CLIENT_ERROR);
}
/**
* Whether this status code is in the HTTP series
* {@link org.springframework.http.HttpStatus.Series#SERVER_ERROR}.
* <p>This is a shortcut for checking the value of {@link #series()}.
* @since 4.0
* @see #series()
*/
public boolean is5xxServerError() {
return (series() == Series.SERVER_ERROR);
}
/**
* Whether this status code is in the HTTP series
* {@link org.springframework.http.HttpStatus.Series#CLIENT_ERROR} or
* {@link org.springframework.http.HttpStatus.Series#SERVER_ERROR}.
* <p>This is a shortcut for checking the value of {@link #series()}.
* @since 5.0
* @see #is4xxClientError()
* @see #is5xxServerError()
*/
public boolean isError() {
return (is4xxClientError() || is5xxServerError());
}
/**
* Return a string representation of this status code.
*/
@Override
public String toString() {
return this.value + " " + name();
}
/**
* Return the {@code HttpStatus} enum constant with the specified numeric value.
* @param statusCode the numeric value of the enum to be returned
* @return the enum constant with the specified numeric value
* @throws IllegalArgumentException if this enum has no constant for the specified numeric value
*/
public static HttpStatus valueOf(int statusCode) {
HttpStatus status = resolve(statusCode);
if (status == null) {
throw new IllegalArgumentException("No matching constant for [" + statusCode + "]");
}
return status;
}
/**
* Resolve the given status code to an {@code HttpStatus}, if possible.
* @param statusCode the HTTP status code (potentially non-standard)
* @return the corresponding {@code HttpStatus}, or {@code null} if not found
* @since 5.0
*/
@Nullable
public static HttpStatus resolve(int statusCode) {
// Use cached VALUES instead of values() to prevent array allocation.
for (HttpStatus status : VALUES) {
if (status.value == statusCode) {
return status;
}
}
return null;
}
/**
* Enumeration of HTTP status series.
* <p>Retrievable via {@link HttpStatus#series()}.
*/
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;
}
/**
* Return the {@code Series} enum constant for the supplied {@code HttpStatus}.
* @param status a standard HTTP status enum constant
* @return the {@code Series} enum constant for the supplied {@code HttpStatus}
* @deprecated as of 5.3, in favor of invoking {@link HttpStatus#series()} directly
*/
@Deprecated
public static Series valueOf(HttpStatus status) {
return status.series;
}
/**
* Return the {@code Series} enum constant for the supplied status code.
* @param statusCode the HTTP status code (potentially non-standard)
* @return the {@code Series} enum constant for the supplied status code
* @throws IllegalArgumentException if this enum has no corresponding constant
*/
public static Series valueOf(int statusCode) {
Series series = resolve(statusCode);
if (series == null) {
throw new IllegalArgumentException("No matching constant for [" + statusCode + "]");
}
return series;
}
/**
* Resolve the given status code to an {@code HttpStatus.Series}, if possible.
* @param statusCode the HTTP status code (potentially non-standard)
* @return the corresponding {@code Series}, or {@code null} if not found
* @since 5.1.3
*/
@Nullable
public static Series resolve(int statusCode) {
int seriesCode = statusCode / 100;
for (Series series : values()) {
if (series.value == seriesCode) {
return series;
}
}
return null;
}
}
}
HttpMethod
package org.springframework.http;
import java.util.HashMap;
import java.util.Map;
import org.springframework.lang.Nullable;
/**
* Enumeration of HTTP request methods. Intended for use
* with {@link org.springframework.http.client.ClientHttpRequest}
* and {@link org.springframework.web.client.RestTemplate}.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @since 3.0
*/
public enum HttpMethod {
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
private static final Map<String, HttpMethod> mappings = new HashMap<>(16);
static {
for (HttpMethod httpMethod : values()) {
mappings.put(httpMethod.name(), httpMethod);
}
}
/**
* Resolve the given method value to an {@code HttpMethod}.
* @param method the method value as a String
* @return the corresponding {@code HttpMethod}, or {@code null} if not found
* @since 4.2.4
*/
@Nullable
public static HttpMethod resolve(@Nullable String method) {
return (method != null ? mappings.get(method) : null);
}
/**
* Determine whether this {@code HttpMethod} matches the given method value.
* @param method the HTTP method as a String
* @return {@code true} if it matches, {@code false} otherwise
* @since 4.2.4
*/
public boolean matches(String method) {
return name().equals(method);
}
}