通用HttpClient封装

一、封装通用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&amp;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&amp;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&amp;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);
	}

}
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大道之简

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值