vertx 异步编程指南 step5-与第三方Web服务集成

本文介绍如何使用Vert.x的HTTP客户端API与GitHub Gist服务集成,实现将wiki页面备份到Gist的功能。文章详细解释了如何配置Web客户端、创建HTTP请求及处理响应。

现代应用程序很少生活在孤立的岛上,因为它们需要与其他(分布式)应用程序和服务集成。通常使用通过HTTP协议公开的API来实现集成。

本节介绍如何使用Vert.x的HTTP客户端API与第三方Web服务进行集成。

场景:备份到GitHub Gist

GitHub的要点服务是广受欢迎的共享代码段到世界各地。其他服务可以使用它,例如中等发布平台,其中指向Gist的链接允许将代码片段嵌入到发布中。

GitHub公开了一个用于获取,创建,更新和删除Gist 详细API该API使用从https://api.github.com/开始的HTTPS端点和JSON有效负载。

虽然许多操作需要使用OAuth身份验证的客户端的授权,但在匿名的情况下创建Gist是可能的我们将利用此功能将我们的维基页面备份为Gist。

一个新的按钮将被添加到wiki索引页面上:

点击备份按钮将触发创建一个Gist:



备份Gist包含每个wiki页面1个文件,内容为原始Markdown文本:

更新数据库服务

在我们深入Web客户端API并执行对其他服务的HTTP请求之前,我们需要更新数据库服务API以一次获取所有wiki页面数据。这对应于要添加到的以下SQL查询db-queries.properties

all-pages-data =从Pages中选择*

一个新的方法被添加到WikiDatabaseService接口:

@Fluent
WikiDatabaseService fetchAllPagesData(Handler<AsyncResult<List<JsonObject>>> resultHandler);

实施WikiDatabaseServiceImpl内容如下:

@Override
public WikiDatabaseService fetchAllPagesData(Handler<AsyncResult<List<JsonObject>>> resultHandler) { 
dbClient.query(sqlQueries.get(SqlQuery.ALL_PAGES_DATA), queryResult -> {
 if (queryResult.succeeded()) { resultHandler.handle(Future.succeededFuture(queryResult.result().getRows())); 
} else { 
LOGGER.error("Database query error", queryResult.cause()); 
resultHandler.handle(Future.failedFuture(queryResult.cause())); } }); 
return this;
}

Web客户端API

Vert.x核心库提供了一个createHttpClient来自vertx上下文对象方法实例io.vertx.core.http.HttpClient提供了用于执行各种HTTP请求的低级方法,并对协议和事件流进行了细粒度的控制。

Web客户端API提供了更简洁的外观,特别是用于简化有效负载数据(非)封送处理。该API以新的依赖关系的形式出现:


<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-web-client</artifactId>
  <version>${vertx.version}</version>
</dependency>

以下是单元测试的示例用法。测试启动一个HTTP服务器,然后它使用Web客户端API执行HTTP GET请求,以检查对服务器的请求是否成功:

@Test
public void start_http_server(TestContext context) {
  Async async = context.async();

  vertx.createHttpServer().requestHandler(req ->
    req.response().putHeader("Content-Type", "text/plain").end("Ok"))
  .listen(8080, context.asyncAssertSuccess(server -> {

    WebClient webClient = WebClient.create(vertx);

      webClient.get(8080, "localhost", "/").send(ar -> {
        if (ar.succeeded()) {
          HttpResponse<Buffer> response = ar.result();
          context.assertTrue(response.headers().contains("Content-Type"));
          context.assertEquals("text/plain", response.getHeader("Content-Type"));
          context.assertEquals("Ok", response.body().toString());
          webClient.close();
          async.complete();
        } else {
          async.resolve(Future.failedFuture(ar.cause()));
        }
      });
    }));
}

创建匿名Gists

我们首先需要一个Web客户端对象来发出对Gist API的HTTP请求:

webClient = WebClient.create(vertx, new WebClientOptions()
  .setSsl(true)
  .setUserAgent("vert-x3"));

tip

由于请求是使用HTTPS完成的,因此我们需要使用SSL支持来配置Web客户端。

GitHub API需要一个有效的User-Agent头部并请求一个GitHub帐户或组织标识符。我们覆盖默认的用户代理,vert-x3但您可以选择使用自己的值。

然后,我们修改HttpServerVerticle该类中的Web路由器配置以添加用于触发备份的新路由:

router.get("/backup").handler(this::backupHandler);

这个处理程序的代码如下:

private void backupHandler(RoutingContext context) {
  dbService.fetchAllPagesData(reply -> {
    if (reply.succeeded()) {

      JsonObject filesObject = new JsonObject();
      JsonObject gistPayload = new JsonObject() (1)
        .put("files", filesObject)
        .put("description", "A wiki backup")
        .put("public", true);

      reply
        .result()
        .forEach(page -> {
          JsonObject fileObject = new JsonObject(); (2)
          filesObject.put(page.getString("NAME"), fileObject);
          fileObject.put("content", page.getString("CONTENT"));
        });

      webClient.post(443, "api.github.com", "/gists") (3)
        .putHeader("Accept", "application/vnd.github.v3+json") (4)
        .putHeader("Content-Type", "application/json")
        .as(BodyCodec.jsonObject()) (5)
        .sendJsonObject(gistPayload, ar -> {  (6)
          if (ar.succeeded()) {
            HttpResponse<JsonObject> response = ar.result();
            if (response.statusCode() == 201) {
              context.put("backup_gist_url", response.body().getString("html_url"));  (7)
              indexHandler(context);
            } else {
              StringBuilder message = new StringBuilder()
                .append("Could not backup the wiki: ")
                .append(response.statusMessage());
              JsonObject body = response.body();
              if (body != null) {
                message.append(System.getProperty("line.separator"))
                  .append(body.encodePrettily());
              }
              LOGGER.error(message.toString());
              context.fail(502);
            }
          } else {
            Throwable err = ar.cause();
            LOGGER.error("HTTP Client error", err);
            context.fail(err);
          }
      });

    } else {
      context.fail(reply.cause());
    }
  });
}
  1. Gist创建请求负载是GitHub API文档中概述的JSON 文档

  2. 每个文件都是files有效负载对象下的一个条目,其中标题是键,值是文本。

  3. Web客户端需要POST在端口443(HTTPS)上发出请求,路径必须是/gists

  4. Accept在请求中使用application/vnd.github.v3+jsonMIME类型是必需的,否则请求失败。指定有效负载是下一行中的JSON对象也很重要。

  5. BodyCodec类提供了一个辅助指定该响应将被直接转换为Vert.x JsonObject实例。也可以使用BodyCodec#json(Class<T>)JSON数据并将其映射到类型的Java对象T(这在引擎盖下使用Jackson数据映射)。

  6. sendJsonObject 是用JSON负载触发HTTP请求的帮助器。

  7. 一旦成功,我们可以遍历JSON数据(html_url关键字)以获取新创建的Gist的用户友好URL。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值