跳到主要内容

6.9 HttpRequest 与 HttpResponse

如果你需要对请求处理进行更多的控制,你可以编写一个接收完整 HttpRequest 的方法。

事实上,有几个更高级的接口可以绑定到控制器方法参数。其中包括:

表 1. 可绑定的 Micronaut 接口

接口描述示例
HttpRequest完整的 HttpRequestString hello(HttpRequest request)
HttpHeaders请求中的所有 HTTP 头String hello(HttpHeaders headers)
HttpParameters请求中存在的所有 HTTP 参数(来自 URI 变量或请求参数)String hello(HttpParameters params)
Cookies请求中所有 cookieString hello(Cookies cookies)
注意

如果需要请求体,则应使用具体的泛型类型来声明 HttpRequest 参数化,例如 HttpRequest<MyClass> 请求。否则,请求体可能无法从请求中获得。

此外,为了完全控制发出的 HTTP 响应,你可以使用 HttpResponse 类的静态工厂方法,这些方法返回一个 MutableHttpResponse

以下示例使用 HttpRequestHttpResponse 对象实现了前面的 MessageController 示例:

请求和响应示例

import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.context.ServerRequestContext;
import reactor.core.publisher.Mono;

@Controller("/request")
public class MessageController {

@Get("/hello") // (1)
public HttpResponse<String> hello(HttpRequest<?> request) {
String name = request.getParameters()
.getFirst("name")
.orElse("Nobody"); // (2)

return HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo"); // (3)
}

}
  1. 该方法被映射到 URI /hello 并接受 HttpRequest
  2. HttpRequest 用于获取名为 name 的查询参数的值。
  3. HttpResponse.ok(T) 方法返回一个带有文本主体的 MutableHttpResponse。一个名为 X-My-Header 的头也被添加到响应中。

HttpRequest 也可以通过 ServerRequestContext 从静态上下文中获得。

使用 ServerRequestContext

import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.context.ServerRequestContext;
import reactor.core.publisher.Mono;

@Controller("/request")
public class MessageController {

@Get("/hello-static") // (1)
public HttpResponse<String> helloStatic() {
HttpRequest<?> request = ServerRequestContext.currentRequest() // (1)
.orElseThrow(() -> new RuntimeException("No request present"));
String name = request.getParameters()
.getFirst("name")
.orElse("Nobody");

return HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo");
}

}
  1. ServerRequestContext 用于检索请求。
警告

一般来说,ServerRequestContext 在响应流中是可用的,但推荐的方法是将请求作为参数使用,如前面的示例所示。如果下游方法中需要请求,则应将其作为参数传递给这些方法。在某些情况下,由于使用了其他线程来发送数据,因此上下文不会传播。

对于 Project Reactor 的用户来说,使用 ServerRequestContext 的另一种选择是使用 Project Reactor 的上下文功能来检索请求。由于 Micronaut 框架使用 Project Reactor 作为其默认的响应流实现,因此 Project Reactor 的用户可以通过在上下文中访问请求而受益。例如:

使用 Project Reactor 上下文

import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.context.ServerRequestContext;
import reactor.core.publisher.Mono;

@Controller("/request")
public class MessageController {

@Get("/hello-reactor")
public Mono<HttpResponse<String>> helloReactor() {
return Mono.deferContextual(ctx -> { // (1)
HttpRequest<?> request = ctx.get(ServerRequestContext.KEY); // (2)
String name = request.getParameters()
.getFirst("name")
.orElse("Nobody");

return Mono.just(HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo"));
});
}

}
  1. Mono 是通过引用上下文创建的
  2. 从上下文中检索请求

使用上下文来检索请求是响应流的最佳方法,因为 Project Reactor 传播上下文,并且它不依赖于像 ServerRequestContext 这样的本地线程。

英文链接