资讯专栏INFORMATION COLUMN

Vert.x入坑须知(3)

CollinPeng / 673人阅读

摘要:对于集成测试,直接模拟实际的环境,再加上合适的,目前看来也还不错。这里给出两个例子集成测试单元测试都是基于写的,各位可以体验其酸爽度。好啦,本期内容就此结束,请保持关注,期待下期继续本系列其他文章入坑须知入坑须知

随着Vert.x进化到3.5.0,本系列也迎来了新篇章。

CORS的新变化

对于CORS,搞Web开发(不论你是前端,还是后端)的同志应该不陌生,尤其是如今微服务盛行的时代,CORS更是最常用的配置项之一。假若你对此还有一点点的疑问,不用问,你已经落伍了!

Vert.x很早就支持了CORS,但到了3.5.0,出于安全性上的考虑,它增加了一个限制:

当allowedOriginPattern为“*”时,allowCredentials不允许为“true”。

这个限制其实起源自协议的限制:

The string "*" cannot be used for a resource that supports credentials.The string "*" cannot be used for a resource that supports credentials.

即:Access-Control-Allow-Origin为“*”时,Access-Control-Allow-Credentials会被忽略,Credentials信息(一般是Cookie)也不会被user-agent发送。大家可以参考这篇文章(英文原版)了解如何安全地设置各个header。

在3.5.0时,当allowedOriginPattern为“*”和allowCredentials为“true”时,Vert.x会产生一个异常,若不处理会导致Verticle不能正常启动。在之前的版本中,不会出现这种情况。

CB for handler

断路器是个好东东,强烈建议在框架设计上就考虑它,以避免粗心的开发者写的代码扰乱其他好代码。在我写dgate和dfx时,对所有对外暴露的服务也都强加了这个限制。

既然CB这么好,是不是动过将其应用到普通Handler上的念头?不过由于Vert.x CB的文档示例中给出的都是清一色的HTTP请求的例子,要想将CB推而广之应用到普通的Handler上还得费点气力。

在dfx中我写了一个工具类,对此需求进行了封装:

public static void withCircuitBreaker(Vertx vertx, CircuitBreaker circuitBreaker
        , Accessible accessible, Map params, Handler successHandler, Handler failureHandler) {
    circuitBreaker.execute(future ->
            vertx.executeBlocking(f -> {
                        try {
                            f.complete(accessible.invoke(params));
                        } catch (Throwable throwable) {
                            f.fail(throwable);
                        }
                    }
                    , result -> {
                        if (result.succeeded()) {
                            future.complete(result.result());
                        } else {
                            future.fail(result.cause());
                        }
                    })
    ).setHandler(result -> {
        if (result.succeeded()) {
            successHandler.handle((Map) result.result());
        } else {
            logger.error("CB[{}] execution failed, cause: ", circuitBreaker.name(), result.cause());
            failureHandler.handle(result.cause());
        }
    });
}

它的使用很简单:

Utils.withCircuitBreaker(vertx, circuitBreaker, accessible, body.getMap()
               , result -> Utils.fireJsonResponse(response, 200, result)
               , throwable -> Utils.fireSingleMessageResponse(response, 500, throwable.getMessage()));

各位可依葫芦画瓢将其改为自己的形式,其中的重点在于以“vertx.executeBlocking”方式来执行Handler的代码。

测试

在稍微正规的队伍中,自动化测试应该已经是一个标准实践了,并且Vert.x对于测试也提供了支持。

不过,我不喜欢。原因有几个:

Vert.x Unit是基于JUnit,而我已经有钟情的测试框架:Spock。相比起JUnit而言,后者简直可以说是Java测试领域的战斗机。

好的单元测试本来就是要尽量少的依赖所用框架,注意这一点之后,尽力将类设计得好测试,这样的结果就是普通的单元测试类编写。既然有让人爽的工具用,也就没有必要去用Vert.x Unit了。

对于集成测试,直接模拟实际的环境,再加上合适的timer,目前看来也还不错。而且Vert.x Unit中也一样需要用timer,这样一来,也就没有必要专门用它了。

为了证明我所言非虚,大家可以去看看dgate和dfx的测试代码。这里给出两个例子:

集成测试

单元测试

都是基于Spock写的,各位可以体验其酸爽度。

运行时外部配置

在本系列第一篇里,我就提出了一个钟意的工程结构组成,但里面没有提到“运行时外部配置文件”这一常见的实践。

经过若干项目的锤炼之后,目前对于这种运行时的外部配置文件,我基本形成了一个固定套路:Groovy DSL + Groovy ConfigSlurper。它俩简直是完成这一任务的绝配,比起Vert.x的提供的json配置文件要爽太多。

看看Gradle的build文件,你就可以知道这种DSL的灵活度可以到什么程度,更何况Groovy的语法对于Java开发者极其友好。

或许有人会觉得Groovy不酷,甚至有点鄙夷,言必称Scala、Clojure、Kotlin、Go或者Rust。对此,哥只想说:作为开发者,最让人鄙夷的是交不出活,客户才不关心你用什么语言呢!

配置DSL的例子:dgate配置

dgate是我写的一个基于vertx的轻量级网关,所有的配置全部通过配置文件来定义,无需数据库。关于它的详细介绍,可以参见其文档。为了说明上一节采用Groovy DSL的灵活度,这里展示几个dgate的配置例子。

静态Mock

利用dgate的mock功能,分离开的前后端开发人员可以并行工作,只需将mock响应配置到dgate的配置文件中就好。

"/summary" {
    expected {
        statusCode = 200
        payload {
            eqLocations = []
            opRateInLast30Days = []
            myOrgs = [
                ["name": "org1", "admin": false]
            ]
        }
    }
}
动态Mock

动态Mock为那些返回动态结果(如某些情况下成功,某些情况下失败)的URL模拟提供了便利。

"/login" {
    required = ["sub", "password"]
    methods = [HttpMethod.GET, HttpMethod.POST]
    expected {
        statusCode = 200
        payload = {
            JWTAuth jwtAuth = Utils.createAuthProvider(Vertx.vertx())
            JWTTokenGenerator tokenGenerator = new JWTTokenGenerator(jwtAuth)
            [token: tokenGenerator.token(["sub": "……", "name": "……", "role": "normal"], 200)]
        }
    }
}

上例将模拟一个实际的动态JWT,这样的好处在于,方便前端/移动端开发直接去完成刷新token或重新登录的过程,而不需要再针对此场景做其他特殊处理。

请注意,为了产生动态结果,此处的payload使用的是闭包,而不像前一例用的是Map。此时,闭包的返回值为Mock响应的结果。

以上的例子已经充分展现了将Groovy DSL作为运行时外部配置的能力,可以说是完胜Vert.x自带的json配置方式。

好啦,本期内容就此结束,请保持关注,期待下期继续!


本系列其他文章:

Vert.x入坑须知(1)

Vert.x入坑须知(2)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70756.html

相关文章

  • Vert.x入坑须知(4)

    摘要:主要是避免引入太多的复杂性,并且出于灵活部署的需要。以应用为例,由于实际上是在上执行,若它被阻塞,即导致后续请求全部无法得到处理。因此,最合适的做法就是对于简单业务,采用异步库。本系列其他文章入坑须知入坑须知入坑须知 最开始觉得这个系列也就最多3篇了不起了(因为事不过三嘛),没曾想居然迎来了第四篇! Kotlin 由于最近决定投身到区块链的学习当中的缘故,出于更好的理解它的基本概念,自...

    summerpxy 评论0 收藏0
  • Vert.x入坑须知(1)

    摘要:轻量级,部署简单。此外,本文也不是入门文档,而是为了预防陷坑而给出的指导意见,故在阅读本文之前还请先仔细阅读的文档。可视作的一个最小部署和运行单元,简单的说,可类比为。,主,负责部署程序中其他的。严格来讲,之后,上述第一点并不完全正确。 一直以来早有将这些年用Vert.x的经验整理一下的想法,奈何天生不是勤快人,直到最近扶墙老师问起,遂成此文。 选择理由 现在想想,我们应该算是国内用V...

    Turbo 评论0 收藏0
  • Vert.x入坑须知(2)

    摘要:这一点其实是非常不妥的,有潜在的安全问题。这次,在项目中终于采用了以它为基础的集群方案。相反,使用一个周期,但针对每个生成一个一次性的,模拟随机发送。同时,要记得用完之后立即释放。 当初创建简书账号的时候曾立下宏愿,希望保持周更,无奈现实残酷,整个5月都处于忙忙碌碌的状态,居然令这个本来并不算太宏伟的目标难以为继,最终导致5月份交了白卷!【好吧,我承认,是我意志不够坚定,太懒了,;)】...

    xialong 评论0 收藏0
  • 使用Vert.x构建Web服务器和消息系统

    摘要:而不是开始,将服务使用多线程的请求重量级的容器。是启动多个轻便单线程的服务器和流量路由到他们。亮点应用程序是事件驱动,异步和单线程的。通过使用事件总线传递消息通信。为了建立一个消息系统,则需要获得该事件总线。 摘要 如果你对Node.js感兴趣,Vert.x可能是你的下一个大事件:一个建立在JVM上一个类似的架构企业制度。 这一部分介绍Vert.x是通过两个动手的例子(基于Vert.x...

    DrizzleX 评论0 收藏0
  • Vert.x Blueprint 系列教程(二) | Vert.x Kue 教程(Web部分)

    摘要:上部分蓝图教程中我们一起探索了如何用开发一个基于消息的应用。对部分来说,如果看过我们之前的蓝图待办事项服务开发教程的话,你应该对这一部分非常熟悉了,因此这里我们就不详细解释了。有关使用实现的教程可参考蓝图待办事项服务开发教程。 上部分蓝图教程中我们一起探索了如何用Vert.x开发一个基于消息的应用。在这部分教程中,我们将粗略地探索一下kue-http模块的实现。 Vert.x Kue ...

    Kerr1Gan 评论0 收藏0

发表评论

0条评论

CollinPeng

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<