包含所有 HTTP 状态码的 Java 枚举

1、简介

Enum(枚举)提供了一种在 Java 编程语言中定义一组命名常量的强大方法。这些常量可用于表示相关值的固定集合,例如 HTTP 状态码。总所周知,互联网上的所有 Web 服务器都会响应 HTTP 状态码作为标准响应码。

本文将带你了解如何创建一个包含所有 HTTP 状态码的 Java 枚举。

2、了解 HTTP 状态码

HTTP 状态码在 Wweb 通信中起着至关重要的作用,它能告知客户端其请求的结果。这些代码分为五类,每一类在 HTTP 协议中都有特定的功能。

3、HTTP 状态码使用枚举的好处

在 Java 中枚举 HTTP 状态码有几个优点,包括:

  • 类型安全:使用 Enum 枚举可确保类型安全,使代码更具可读性和可维护性
  • 分组常量:Enum 枚举将相关常量组合在一起,以清晰和结构化的方式处理固定值集合
  • 避免硬编码:将 HTTP 状态码定义为枚举,有助于防止硬编码字符串或整数造成的错误
  • 增强清晰度和可维护性:这种方法通过增强清晰度、减少错误和提高代码的可维护性,促进软件开发的最佳实践

4、基本做法

为了在 Java 应用中有效管理 HTTP 状态码,我们可以定义一个枚举来封装所有标准 HTTP 状态码及其描述。

这种方法可以让我们充分利用枚举类型安全和代码清晰的优势。

定义 HttpStatus 枚举:

public enum HttpStatus {
    CONTINUE(100, "Continue"),
    SWITCHING_PROTOCOLS(101, "Switching Protocols"),
    OK(200, "OK"),
    CREATED(201, "Created"),
    ACCEPTED(202, "Accepted"),
    MULTIPLE_CHOICES(300, "Multiple Choices"),
    MOVED_PERMANENTLY(301, "Moved Permanently"),
    FOUND(302, "Found"),
    BAD_REQUEST(400, "Bad Request"),
    UNAUTHORIZED(401, "Unauthorized"),
    FORBIDDEN(403, "Forbidden"),
    NOT_FOUND(404, "Not Found"),
    INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
    NOT_IMPLEMENTED(501, "Not Implemented"),
    BAD_GATEWAY(502, "Bad Gateway"),
    UNKNOWN(-1, "Unknown Status");

    private final int code;
    private final String description;

    HttpStatus(int code, String description) {
        this.code = code;
        this.description = description;
    }

    public static HttpStatus getStatusFromCode(int code) {
        for (HttpStatus status : HttpStatus.values()) {
            if (status.getCode() == code) {
                return status;
            }
        }
        return UNKNOWN;
    }

    public int getCode() {
        return code;
    }

    public String getDescription() {
        return description;
    }
}

该枚举中的每个常量都与一个 int code 和一个字符串描述相关联,构造函数会初始化这些值。此外,我们还提供了 getter 方法来检索这些值。

创建单元测试,测试 HttpStatus 枚举类:

@Test
public void givenStatusCode_whenGetCode_thenCorrectCode() {
    assertEquals(100, HttpStatus.CONTINUE.getCode());
    assertEquals(200, HttpStatus.OK.getCode());
    assertEquals(300, HttpStatus.MULTIPLE_CHOICES.getCode());
    assertEquals(400, HttpStatus.BAD_REQUEST.getCode());
    assertEquals(500, HttpStatus.INTERNAL_SERVER_ERROR.getCode());
}

@Test
public void givenStatusCode_whenGetDescription_thenCorrectDescription() {
    assertEquals("Continue", HttpStatus.CONTINUE.getDescription());
    assertEquals("OK", HttpStatus.OK.getDescription());
    assertEquals("Multiple Choices", HttpStatus.MULTIPLE_CHOICES.getDescription());
    assertEquals("Bad Request", HttpStatus.BAD_REQUEST.getDescription());
    assertEquals("Internal Server Error", HttpStatus.INTERNAL_SERVER_ERROR.getDescription());
}

如上,验证了 getCode()getDescription() 方法是否能返回各种 HTTP 状态码的正确值。第一个测试方法检查 getCode() 方法是否为每个枚举常量返回正确的 int 状态码。同样,第二个测试方法确保 getDescription() 方法返回适当的字符串描述。

5、使用 Apache HttpComponents

Apache HttpComponents 是一个用于 HTTP 通信的流行库。要在 Maven 中使用它,需要在 pom.xml 中加入以下依赖:

<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.3.1</version>
</dependency>

你可以在 Maven Central 上找到有关该依赖的更多详细信息。

我们可以使用 HttpStatus 枚举来处理 HTTP 响应:

@Test
public void givenHttpRequest_whenUsingApacheHttpComponents_thenCorrectStatusDescription() throws IOException {
    CloseableHttpClient httpClient = HttpClients.createDefault();
    HttpGet request = new HttpGet("http://example.com");
    try (CloseableHttpResponse response = httpClient.execute(request)) {
        String reasonPhrase = response.getStatusLine().getReasonPhrase();
        assertEquals("OK", reasonPhrase);
    }
}

如上,首先使用 createDefault() 方法创建一个 CloseableHttpClient 实例。此外,该客户端还负责发出 HTTP 请求。然后,使用 new HttpGet("http://example.com")http://example.com 发送 HTTP GET 请求。使用 execute() 方法执行请求后,我们会收到一个 CloseableHttpResponse 对象。

我们使用 response.getStatusLine().getStatusCode() 从响应中提取状态码。然后,使用 HttpStatusUtil.getStatusDescription() 获取与状态码相关的状态描述。

最后,使用 assertEquals() 来确保描述与预期值相匹配,从而验证状态码处理是否准确。

6、使用 RestTemplate

Spring 的 RestTemplate 也能受益于 HttpStatus 枚举,用于处理 HTTP 响应。

首先在 pom.xml 中加入以下依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>6.1.11</version>
</dependency>

你可以在 Maven Central 上找到有关该依赖的更多详细信息。

来看看如何使用一个简单的实现来利用这种方法:

@Test
public void givenHttpRequest_whenUsingSpringRestTemplate_thenCorrectStatusDescription() {
    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<String> response = restTemplate.getForEntity("http://example.com", String.class);
    int statusCode = response.getStatusCode().value();
    String statusDescription = HttpStatus.getStatusFromCode(statusCode).getDescription();
    assertEquals("OK", statusDescription);
}

如上,我们创建了一个 RestTemplate 实例来执行 HTTP GET 请求。获取响应实体对象后,我们使用 response.getStatusCode().value() 提取状态码。然后,我们将此状态码传递给 HttpStatus.getStatusFromCode.getDescription(),以获取相应的状态描述。

7、使用 OkHttp 库

OkHttp 是 Java 中另一个广泛使用的 HTTP 客户端库。

pom.xml 中添加以下依赖:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version>
</dependency>

你可以在 Maven Central 上找到有关该依赖关系的更多详细信息。

现在,将 HttpStatus 枚举与 OkHttp 集成,以处理响应:

@Test
public void givenHttpRequest_whenUsingOkHttp_thenCorrectStatusDescription() throws IOException {
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder()
      .url("http://example.com")
      .build();
    try (Response response = client.newCall(request).execute()) {
        int statusCode = response.code();
        String statusDescription = HttpStatus.getStatusFromCode(statusCode).getDescription();
        assertEquals("OK", statusDescription);
    }
}

在这个测试中,我们初始化了一个 OkHttpClient 实例,并使用 Request.Builder() 创建了一个 HTTP GET 请求。然后,我们使用 client.newCall(request).execute() 方法执行请求并获取响应对象。我们使用 response.code() 方法提取状态码,并将其传递给 HttpStatus.getStatusFromCode.getDescription() 方法,以获取状态描述。

8、总结

本文介绍了如何使用 Java 枚举来表示 HTTP 状态码,从而提高代码的可读性、可维护性和类型安全性。

无论选择简单的枚举定义,还是将其与 Apache HttpComponents、Spring RestTemplate 或 OkHttp 等各种 Java 库一起使用,枚举都足够强大,可以在 Java 中处理固定的相关常量集。


Ref:https://www.baeldung.com/java-enum-http-status