Vert.x Web Validation

Vert.x Web Validation可以帮助您解析校验您的参数以及来自请求体中的内容

您可以做到如下事情:

  • 解析校验请求参数,也可以序列化和分解

  • 解析和校验请求体(包括json和form格式)

  • 配置请求方式

  • 允许同一路由中的不同请求体同时进行的解析和验证

  • 自定义解析校验规则

  • 管理解析校验失败的处理逻辑

它用 Vert.x Json Schema 来定义您的请求参数和请求体

使用 Vert.x Web Validation

为了使用Vert.x Web Validation,请在您的build模块中添加如下的依赖:

  • Maven ( pom.xml 文件):

<dependency>
 <groupId>io.vertx</groupId>
 <artifactId>vertx-web-validation</artifactId>
 <version>4.4.0</version>
</dependency>
  • Gradle ( build.gradle 文件):

dependencies {
 compile 'io.vertx:vertx-web-validation:4.4.0'
}

不使用 Vert.x Web Validation 时

当您接收到一个HTTP请求时,您经常需要解析请求中的参数以及请求体:

router
  .get("/user")
  .handler(routingContext -> {
    // 接收 aParam
    String aParamUnparsed = routingContext.queryParam("aParam").get(0);
    if (aParamUnparsed == null) {
      routingContext.fail(400);
      return;
    }
    // 解析 aParam
    int aParam;
    try {
      aParam = Integer.parseInt(aParamUnparsed);
    } catch (NumberFormatException e) {
      routingContext.fail(400, e);
      return;
    }
    // 校验aParam是否大于 100
    if (aParam > 100) {
      routingContext.fail(400);
      return;
    }
    // aParam接收完毕,现在我们可以专注于处理请求的业务逻辑
  });

Vert.x Web Validation 提供了非常好用的API来构建一个解析和校验请求的 handler

router
  .get("/user")
  .handler(
    ValidationHandlerBuilder
      .create(schemaParser)
      .queryParameter(param(
        "aParam",
        intSchema().with(maximum(100))
      ))
      .build()
  )
  .handler(routingContext -> {
    RequestParameters parameters = routingContext.get(ValidationHandler.REQUEST_CONTEXT_KEY);
    int aParam = parameters.queryParameter("aParam").getInteger();
    // 处理请求的业务逻辑
  });

创建 ValidationHandler

这个模块提供了一个简单好用的 builder API 来创建 ValidationHandler , 这个 Handler 用于解析和校验请求。 您可以使用 ValidationHandlerBuilder.create 方法以创建该 builder 对象。 提供的 SchemaParser 对象可被用于解析使用 Vert.x Json Schema DSL 创建的所有数据格式。

定义参数

您可以在请求中4个不同的位置来定义参数: query, cookie, header, path。

每个参数都由一个 ParameterProcessor 所接收, 您可以用 Parameters 中提供的方法来创建这个 Processor

ValidationHandlerBuilder
  .create(schemaParser)
  .pathParameter(Parameters.param("myPathParam", stringSchema()))
  .queryParameter(Parameters.optionalParam("myQueryParam", intSchema()));

注意:所有这些方法都需要一个schema参数,validator要用这个schema做校验操作。这个schema也可以用来指定正确的parser

尽管请求头和路径参数只允许传简单参数,但是 query 和cookie允许传复杂参数(url参数的或层次较深的对象);

ValidationHandlerBuilder
  .create(schemaParser)
  .queryParameter(Parameters.explodedParam(
    "myArray",
    arraySchema().items(stringSchema())
  ))  // 接收 myArray=item1&myArray=item2
  .queryParameter(Parameters.deepObjectParam(
    "myDeepObject",
    objectSchema()
      .property("name", stringSchema())
  )); // 接收 myDeepObject[name]=francesco

更多关于参数的文档 可见于 Parameters

定义请求体

每个请求体类型都被符合某个 Content-type 请求头的 ParameterProcessor 所解析。如果没有找到匹配的请求体处理器,除非您指定了下述的解析器,否则验证不会失败

您可以用 Bodies 提供的方法来轻松创建这些解析器。

ObjectSchemaBuilder bodySchemaBuilder = objectSchema()
  .property("username", stringSchema())
  .property("password", stringSchema());
ValidationHandlerBuilder
  .create(schemaParser)
  .body(Bodies.json(bodySchemaBuilder))
  .body(Bodies.formUrlEncoded(bodySchemaBuilder));

这个例子中 ValidationHandler 可以管理两个不同的请求体类型(同时解析校验) 尤其是form类型的请求体 会被转换成json。当您接收解析后的结果时,不需要关心请求体时form还是json。

关于请求体解析器的更多信息,见于 Bodies

定义请求断言

您可以在 ValidationHandler 中用 RequestPredicate 来定义请求断言 ,例如 断言请求体非空:

ValidationHandlerBuilder
  .create(schemaParser)
  .predicate(RequestPredicate.BODY_REQUIRED);

构建 ValidationHandler

在您配置了所有的 '参数'、'请求体'、'断言’之后, 您可以创建 ValidationHandler :

router
  .get("/user")
  .handler(
    ValidationHandlerBuilder
      .create(schemaParser)
      .build()
  );

使用解析的参数和请求体

ValidationHandler 会把解析到的参数放入 RoutingContext :

router
  .get("/user")
  .handler(
    ValidationHandlerBuilder
      .create(schemaParser)
      .queryParameter(Parameters.explodedParam(
        "myArray",
        arraySchema().items(stringSchema())
      ))
      .body(Bodies.json(objectBodySchemaBuilder))
      .body(Bodies.formUrlEncoded(objectBodySchemaBuilder))
      .build()
  ).handler(routingContext -> {
    RequestParameters parameters = routingContext.get(ValidationHandler.REQUEST_CONTEXT_KEY);
    JsonArray myArray = parameters.queryParameter("myArray").getJsonArray();
    JsonObject body = parameters.body().getJsonObject();
  });

处理失败

ValidationHandler 每次遇到解析错误或者校验错误,它会让 RoutingContext 以400的状态码结束请求, 然后抛出 BadRequestException 。 想要了解如何处理请求失败,请查看 Vert.x Web docerrorHandler 方法.

BadRequestException 的子类如下:

例如:

router.errorHandler(400, routingContext -> {
  if (routingContext.failure() instanceof BadRequestException) {
    if (routingContext.failure() instanceof ParameterProcessorException) {
      // 解析或校验参数失败
    } else if (routingContext.failure() instanceof BodyProcessorException) {
      // 解析或校验请求体失败
    } else if (routingContext.failure() instanceof RequestPredicateException) {
      // 不满足请求断言
    }
  }
 });

BadRequestException 也提供一个便捷的 toJson 方法,它将异常转换成了Json。

请注意 ValidationHandler 的设计为 迅速失败 ,即一旦遇到错误,ValidationHandler 将置 RoutingContext 为失败状态。