Using Spring ResponseEntity to Manipulate the HTTP Response – 使用Spring ResponseEntity来操纵HTTP响应

最后修改: 2018年 7月 3日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

Using Spring, we usually have many ways to achieve the same goal, including fine-tuning HTTP responses.

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

In this short tutorial, we’ll see how to set the body, status, and headers of an HTTP response using ResponseEntity.

在这个简短的教程中,我们将看到如何使用ResponseEntity设置HTTP响应的body、status和headers。

2. ResponseEntity

2.ResponseEntity

ResponseEntity represents the whole HTTP response: status code, headers, and body. As a result, we can use it to fully configure the HTTP response.

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

If we want to use it, we have to return it from the endpoint; Spring takes care of the rest.

如果我们想使用它,我们必须从端点返回它;Spring会处理其他的事情。

ResponseEntity is a generic type. Consequently, we can use any type as the response body:

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

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

Since we specify the response status programmatically, we can return with different status codes for different scenarios:

由于我们以编程方式指定响应状态,我们可以针对不同的情况返回不同的状态代码。

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

Additionally, we can set HTTP headers:

此外,我们还可以设置HTTP头信息。

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

Furthermore, ResponseEntity provides two nested builder interfaces: HeadersBuilder and its subinterface, BodyBuilder. Therefore, we can access their capabilities through the static methods of ResponseEntity.

此外,ResponseEntity 提供了两个嵌套的构建器接口HeadersBuilder及其子接口,BodyBuilder。因此,我们可以通过ResponseEntity的静态方法访问它们的功能。

The simplest case is a response with a body and HTTP 200 response code:

最简单的情况是一个有正文和HTTP 200响应代码的响应。

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

For the most popular HTTP status codes we get static methods:

对于最流行的HTTP状态代码,我们得到了静态方法。

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

In addition, we can use the BodyBuilder status(HttpStatus status) and the BodyBuilder status(int status) methods to set any HTTP status.

此外,我们可以使用BodyBuilder status(HttpStatus status)BodyBuilder status(int status)方法来设置任何HTTP状态。

Finally, with ResponseEntity<T> BodyBuilder.body(T body) we can set the HTTP response body:

最后,通过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));
}

We can also set custom headers:

我们还可以设置自定义标题。

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

Since BodyBuilder.body() returns a ResponseEntity instead of BodyBuilder, it should be the last call.

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

Note that with HeaderBuilder we can’t set any properties of the response body.

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

While returning ResponseEntity<T> object from the controller, we might get an exception or error while processing the request and would like to return error-related information to the user represented as some other type, let’s say E.

当从控制器返回ResponseEntity<T>对象时,我们可能在处理请求时得到一个异常或错误,并希望将与错误相关的信息以其他类型的形式返回给用户,比方说E

Spring 3.2 brings support for a global @ExceptionHandler with the new @ControllerAdvice annotation, which handles these kinds of scenarios. For in-depth details, refer to our existing article here.

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

While ResponseEntity is very powerful, we shouldn’t overuse it. In simple cases, there are other options that satisfy our needs and they result in much cleaner code.

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

3. Alternatives

3.替代品

3.1. @ResponseBody

3.1@ResponseBody

In classic Spring MVC applications, endpoints usually return rendered HTML pages. Sometimes we only need to return the actual data; for example, when we use the endpoint with AJAX.

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

In such cases, we can mark the request handler method with @ResponseBody, and Spring treats the result value of the method as the HTTP response body itself.

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

For more information, this article is a good place to start.

欲了解更多信息,这篇文章是一个好的开始

3.2. @ResponseStatus

3.2.@ResponseStatus

When an endpoint returns successfully, Spring provides an HTTP 200 (OK) response. If the endpoint throws an exception, Spring looks for an exception handler that tells which HTTP status to use.

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

We can mark these methods with @ResponseStatus, and therefore, Spring returns with a custom HTTP status.

我们可以用@ResponseStatus来标记这些方法,因此,Spring 返回的是自定义的HTTP状态

For more examples, please visit our article about custom status codes.

更多的例子,请访问我们关于custom status codes的文章。

3.3. Manipulate the Response Directly

3.3.直接操纵响应

Spring also lets us access the javax.servlet.http.HttpServletResponse object directly; we only have to declare it as a method argument:

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

Since Spring provides abstractions and additional capabilities above the underlying implementation, we shouldn’t manipulate the response this way.

由于Spring提供了高于底层实现的抽象和额外能力,我们不应该以这种方式操纵响应

4. Conclusion

4.总结

In this article, we discussed multiple ways to manipulate the HTTP response in Spring, and examined their benefits and drawbacks.

在这篇文章中,我们讨论了在Spring中操作HTTP响应的多种方法,并研究了它们的优点和缺点。

As usual, the examples are available over on GitHub.

像往常一样,这些例子可以在GitHub上找到over