ServerRequest 和 ServerResponse 是不可变的接口,它们为 JDK 8 提供了对 HTTP 请求和响应的友好访问,包括头信息、正文、方法和状态代码。
ServerRequest
ServerRequest 提供了对 HTTP 方法、URI、头信息和查询参数的访问,而对正文的访问则通过 body 方法提供。
下面的例子将请求正文提取为一个字符串:
String string = request.body(String.class);
下面的例子将主体提取为 List<Person>,其中 Person 对象是从序列化的形式(如 JSON 或 XML)解码的:
List<Person> people = request.body(new ParameterizedTypeReference<List<Person>>() {});
下面的例子显示了如何访问参数:
MultiValueMap<String, String> params = request.params();
ServerResponse
ServerResponse 提供了对 HTTP 响应的访问,由于它是不可变的,你可以使用构建方法来创建它。你可以使用构建器来设置响应状态,添加响应头,或提供一个主体。下面的例子创建了一个带有 JSON 内容的 200(OK)响应:
Person person = ...ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person);
下面的例子显示了如何建立一个带有 Location 头和无正文的 201(CREATED)响应:
URI location = ...ServerResponse.created(location).build();
你也可以使用一个异步的结果作为主体,形式为 CompletableFuture、Publisher 或 ReactiveAdapterRegistry 支持的任何其他类型。比如说:
Mono<Person> person = webClient.get().retrieve().bodyToMono(Person.class);ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person);
如果不仅仅是主体,还有状态或头信息都是基于异步类型,你可以使用 ServerResponse 上的静态异步方法,它接受CompletableFuture<ServerResponse>、Publisher<ServerResponse>或 ReactiveAdapterRegistry支持的任何其他异步类型。比如说:
Mono<ServerResponse> asyncResponse = webClient.get().retrieve().bodyToMono(Person.class).map(p -> ServerResponse.ok().header("Name", p.name()).body(p));ServerResponse.async(asyncResponse);
服务器发送的事件可以通过 ServerResponse 的静态 sse 方法提供。该方法提供的构建器允许你发送字符串,或其他对象作为 JSON。比如说:
public RouterFunction<ServerResponse> sse() {return route(GET("/sse"), request -> ServerResponse.sse(sseBuilder -> {// 在某处保存 sseBuilder 对象。}));}// 在其他一些线程中,发送一个字符串sseBuilder.send("Hello world");// 或者一个对象,它将被转化为 JSONPerson person = ...sseBuilder.send(person);// 通过使用其他方法来定制该事件sseBuilder.id("42").event("sse event").data(person);// 并在某一时刻完成sseBuilder.complete();
Handler Classes / 处理程序类
我们可以把处理程序函数写成一个 lambda,如下例所示:
HandlerFunction<ServerResponse> helloWorld =request -> ServerResponse.ok().body("Hello World");
这很方便,但在一个应用程序中,我们需要多个函数,而多个内联的 lambda 会变得很混乱。因此,将相关的处理函数组合到一个处理类中是很有用的,它的作用类似于基于注解的应用程序中的 @Controller。例如,下面这个类暴露了一个反应式的人名库:
import static org.springframework.http.MediaType.APPLICATION_JSON;import static org.springframework.web.reactive.function.server.ServerResponse.ok;public class PersonHandler {private final PersonRepository repository;public PersonHandler(PersonRepository repository) {this.repository = repository;}// 处理函数,从数据库走概率查询所有的 person 对象,并以 json 格式响应public ServerResponse listPeople(ServerRequest request) {List<Person> people = repository.allPeople();return ok().contentType(APPLICATION_JSON).body(people);}public ServerResponse createPerson(ServerRequest request) throws Exception {Person person = request.body(Person.class);repository.savePerson(person);return ok().build();}// getPerson 是一个处理函数,返回一个单一的 Person,由 id 路径变量识别。// 我们从资源库中检索该 Person,并创建一个 JSON 响应,如果它被找到// 如果没有找到,我们返回一个 404 Not Found 响应。public ServerResponse getPerson(ServerRequest request) {int personId = Integer.parseInt(request.pathVariable("id"));Person person = repository.getPerson(personId);if (person != null) {return ok().contentType(APPLICATION_JSON).body(person);}else {return ServerResponse.notFound().build();}}}
Validation / 校验
一个功能端点可以使用 Spring 的验证设施 来对请求体进行验证。例如,给定一个自定义的 Spring 验证器的实现,用于 Person.Case 的验证:
public class PersonHandler {// 创建验证器实例private final Validator validator = new PersonValidator();// ...public ServerResponse createPerson(ServerRequest request) {Person person = request.body(Person.class);validate(person); // 验证参数repository.savePerson(person);return ok().build();}private void validate(Person person) {Errors errors = new BeanPropertyBindingResult(person, "person");validator.validate(person, errors);// 如果出现错误,这引发异常: 400 状态的响应if (errors.hasErrors()) {throw new ServerWebInputException(errors.toString());}}}
处理程序也可以通过创建和注入一个基于 LocalValidatorFactoryBean 的全局 Validator 实例来使用标准的 bean 验证API(JSR-303)。参见 Spring 验证。
