使用 Spring ResponseEntity 处理 HTTP 响应

1、概览

本文将带你了解如何使用 ResponseEntity 设置 HTTP 响应的 Body、Status 和 Header。

2、ResponseEntity

ResponseEntity 表示整个 HTTP 响应:状态码、Header 和 Body。因此,可以用它来完全配置 HTTP 响应。只需从端点返回它,Spring 就会处理接下来的所有事情。

ResponseEntity 是一个泛型类。因此,可以使用任何类型作为响应体:

@GetMapping("/hello")
ResponseEntity<String> hello() {
    return new ResponseEntity<>("Hello World!", HttpStatus.OK);
}

通过编程式,可以针对不同情况返回不同的 HTTP 状态码:

@GetMapping("/age")
ResponseEntity<String> age(
  @RequestParam("yearOfBirth") int yearOfBirth) {
 
    if (isInFuture(yearOfBirth)) {
        return new ResponseEntity<>(
          "Year of birth cannot be in the future", 
          HttpStatus.BAD_REQUEST); // 400
    }

    return new ResponseEntity<>(
      "Your age is " + calculateAge(yearOfBirth), 
      HttpStatus.OK); // 200s
}

还可以设置 HTTP 响应头:

@GetMapping("/customHeader")
ResponseEntity<String> customHeader() {
    HttpHeaders headers = new HttpHeaders();
    headers.add("Custom-Header", "foo");
        
    return new ResponseEntity<>(
      "Custom header set", headers, HttpStatus.OK);
}

ResponseEntity 还提供了两个嵌套的 Builder 接口:HeadersBuilder 及其子接口 BodyBuilder。可以通过 ResponseEntity 的静态方法访问它们。

如下,设置 200 响应并且指定响应体:

@GetMapping("/hello")
ResponseEntity<String> hello() {
    return ResponseEntity.ok("Hello World!");
}

对于最常用的 HTTP 状态码,都提供了静态方法:

BodyBuilder accepted();
BodyBuilder badRequest();
BodyBuilder created(java.net.URI location);
HeadersBuilder<?> noContent();
HeadersBuilder<?> notFound();
BodyBuilder ok();

还可以使用 BodyBuilder status(HttpStatus status)BodyBuilder status(int status) 方法来设置其他 HTTP 状态码。

可以通过 ResponseEntity<T> BodyBuilder.body(T body) 设置 HTTP 响应体:

@GetMapping("/age")
ResponseEntity<String> age(@RequestParam("yearOfBirth") int yearOfBirth) {
    if (isInFuture(yearOfBirth)) {
        return ResponseEntity.badRequest()
            .body("Year of birth cannot be in the future");
    }

    return ResponseEntity.status(HttpStatus.OK)
        .body("Your age is " + calculateAge(yearOfBirth));
}

还可以设置自定义 Header:

@GetMapping("/customHeader")
ResponseEntity<String> customHeader() {
    return ResponseEntity.ok()
        .header("Custom-Header", "foo")
        .body("Custom header set");
}

由于 BodyBuilder.body() 返回的是 ResponseEntity 而不是 BodyBuilder,所以它应该最后调用。

注意,使用 HeaderBuilder 时,不能设置响应体的任何属性。

3、替代方案

3.1、@ResponseBody

在经典的 Spring MVC 应用中,端点通常会返回已渲染的 HTML 页面。有时,只需要返回实际数据;例如,返回 JSON 数据。

在这种情况下,可以用 @ResponseBody 来标记 Handler 方法,这样 Spring 就会将该方法的结果值视为 HTTP 响应体本身。

3.2、@ResponseStatus

当端点成功返回时,Spring 会提供 HTTP 200(OK)响应。如果端点抛出异常,Spring 会寻找一个异常 Handler,告知使用哪种 HTTP 状态。

可以用 @ResponseStatus 标记这些方法,这样 Spring 就会返回自定义的 HTTP 状态码。

3.3、直接操作 Response

Spring 还允许我们直接访问 javax.servlet.http.HttpServletResponse 对象。

只需将其声明为方法参数即可:

@GetMapping("/manual")
void manual(HttpServletResponse response) throws IOException {
    response.setHeader("Custom-Header", "foo");
    response.setStatus(200);
    response.getWriter().println("Hello World!");
}

4、总结

本文介绍了如何在 Spring 中通过 ResponseEntity 来操作响应,以及可代替 ResponseEntity 的方式有哪些。


Ref:https://www.baeldung.com/spring-response-entity