6.9 HttpRequest 与 HttpResponse
如果你需要对请求处理进行更多的控制,你可以编写一个接收完整 HttpRequest 的方法。
事实上,有几个更高级的接口可以绑定到控制器方法参数。其中包括:
表 1. 可绑定的 Micronaut 接口
接口 | 描述 | 示例 |
---|---|---|
HttpRequest | 完整的 HttpRequest | String hello(HttpRequest request) |
HttpHeaders | 请求中的所有 HTTP 头 | String hello(HttpHeaders headers) |
HttpParameters | 请求中存在的所有 HTTP 参数(来自 URI 变量或请求参数) | String hello(HttpParameters params) |
Cookies | 请求中所有 cookie | String hello(Cookies cookies) |
如果需要请求体,则应使用具体的泛型类型来声明 HttpRequest 参数化,例如 HttpRequest<MyClass>
请求。否则,请求体可能无法从请求中获得。
此外,为了完全控制发出的 HTTP 响应,你可以使用 HttpResponse 类的静态工厂方法,这些方法返回一个 MutableHttpResponse。
以下示例使用 HttpRequest 和 HttpResponse 对象实现了前面的 MessageController
示例:
请求和响应示例
- Java
- Groovy
- Kotlin
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)
}
}
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")
class MessageController {
@Get("/hello") // (1)
HttpResponse<String> hello(HttpRequest<?> request) {
String name = request.parameters
.getFirst("name")
.orElse("Nobody") // (2)
HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo") // (3)
}
}
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
import reactor.util.context.ContextView
@Controller("/request")
class MessageController {
@Get("/hello") // (1)
fun hello(request: HttpRequest<*>): HttpResponse<String> {
val name = request.parameters
.getFirst("name")
.orElse("Nobody") // (2)
return HttpResponse.ok("Hello $name!!")
.header("X-My-Header", "Foo") // (3)
}
}
- 该方法被映射到 URI
/hello
并接受 HttpRequest - HttpRequest 用于获取名为
name
的查询参数的值。 - HttpResponse.ok(T) 方法返回一个带有文本主体的 MutableHttpResponse。一个名为
X-My-Header
的头也被添加到响应中。
HttpRequest 也可以通过 ServerRequestContext 从静态上下文中获得。
使用 ServerRequestContext
- Java
- Groovy
- Kotlin
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");
}
}
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")
class MessageController {
@Get("/hello-static") // (1)
HttpResponse<String> helloStatic() {
HttpRequest<?> request = ServerRequestContext.currentRequest() // (1)
.orElseThrow(() -> new RuntimeException("No request present"))
String name = request.parameters
.getFirst("name")
.orElse("Nobody")
HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo")
}
}
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
import reactor.util.context.ContextView
@Controller("/request")
class MessageController {
@Get("/hello-static") // (1)
fun helloStatic(): HttpResponse<String> {
val request: HttpRequest<*> = ServerRequestContext.currentRequest<Any>() // (1)
.orElseThrow { RuntimeException("No request present") }
val name = request.parameters
.getFirst("name")
.orElse("Nobody")
return HttpResponse.ok("Hello $name!!")
.header("X-My-Header", "Foo")
}
}
- ServerRequestContext 用于检索请求。
一般来说,ServerRequestContext 在响应流中是可用的,但推荐的方法是将请求作为参数使用,如前面的示例所示。如果下游方法中需要请求,则应将其作为参数传递给这些方法。在某些情况下,由于使用了其他线程来发送数据,因此上下文不会传播。
对于 Project Reactor 的用户来说,使用 ServerRequestContext 的另一种选择是使用 Project Reactor 的上下文功能来检索请求。由于 Micronaut 框架使用 Project Reactor 作为其默认的响应流实现,因此 Project Reactor 的用户可以通过在上下文中访问请求而受益。例如:
使用 Project Reactor 上下文
- Java
- Groovy
- Kotlin
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"));
});
}
}
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")
class MessageController {
@Get("/hello-reactor")
Mono<HttpResponse<String>> helloReactor() {
Mono.deferContextual(ctx -> { // (1)
HttpRequest<?> request = ctx.get(ServerRequestContext.KEY) // (2)
String name = request.parameters
.getFirst("name")
.orElse("Nobody")
Mono.just(HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo"))
})
}
}
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
import reactor.util.context.ContextView
@Controller("/request")
class MessageController {
@Get("/hello-reactor")
fun helloReactor(): Mono<HttpResponse<String>?>? {
return Mono.deferContextual { ctx: ContextView -> // (1)
val request = ctx.get<HttpRequest<*>>(ServerRequestContext.KEY) // (2)
val name = request.parameters
.getFirst("name")
.orElse("Nobody")
Mono.just(HttpResponse.ok("Hello $name!!")
.header("X-My-Header", "Foo"))
}
}
}
- Mono 是通过引用上下文创建的
- 从上下文中检索请求
使用上下文来检索请求是响应流的最佳方法,因为 Project Reactor 传播上下文,并且它不依赖于像 ServerRequestContext 这样的本地线程。