使用Spring的ResponseEntity操作HTTP响应

2023/05/12

1. 简介

使用Spring,我们通常有很多方法来实现相同的目标,包括微调HTTP响应。

在这个简短的教程中,我们将了解如何使用ResponseEntity设置HTTP响应的正文、状态和标头。

2. ResponseEntity

ResponseEntity表示整个HTTP响应:状态代码、标头和正文,因此,我们可以使用它来完全配置HTTP响应。

如果我们想使用它,我们必须从端点返回它;Spring负责其余的工作。

ResponseEntity是一种泛型类型,因此,我们可以使用任何类型作为响应主体:

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

由于我们以编程方式指定响应状态,因此我们可以针对不同的场景返回不同的状态代码:

@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);
    }

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

此外,我们可以设置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提供了两个嵌套的构建器接口:HeadersBuilder及其子接口BodyBuilder。因此,我们可以通过ResponseEntity的静态方法访问它们的功能。

最简单的情况是带有正文和HTTP 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 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));
}

我们还可以设置自定义标头:

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

由于BodyBuilder.body()返回的是ResponseEntity而不是BodyBuilder,因此它应该是最后一次调用。

请注意,使用HeaderBuilder我们无法设置响应主体的任何属性。

从控制器返回ResponseEntity<T>对象时,我们可能会在处理请求时遇到异常或错误,并希望将与错误相关的信息表示为某种其他类型(比方说E)返回给用户

Spring 3.2通过新的@ControllerAdvice注解带来了对全局@ExceptionHandler的支持,它可以处理这些类型的场景。有关详细信息,请参阅我们现有的文章

虽然ResponseEntity非常强大,但我们不应该过度使用它。在简单的情况下,还有其他选项可以满足我们的需求,并且它们会产生更简洁的代码。

3. 备选方案

3.1 @ResponseBody

在经典的Spring MVC应用程序中,端点通常返回呈现的HTML页面。有时我们只需要返回实际数据;例如,当我们将端点与AJAX一起使用时。

在这种情况下,我们可以使用@ResponseBody标注请求处理程序方法,Spring将该方法的结果值视为HTTP响应主体本身。

有关更多信息,本文是一个很好的起点

3.2 @ResponseStatus

当端点成功返回时,Spring提供HTTP 200(OK)响应。如果端点抛出异常,Spring会查找异常处理程序来告知要使用的HTTP状态。

我们可以使用@ResponseStatus标注这些方法,因此,Spring返回一个自定义的HTTP状态

有关更多示例,请访问我们关于自定义状态代码的文章。

3.3 直接操纵响应

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!");
}

由于Spring在底层实现之上提供了抽象和附加功能,因此我们不应该以这种方式操作响应

4. 总结

在本文中,我们讨论了在Spring中操作HTTP响应的多种方法,并检查了它们的优缺点。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章