拦截器(Interceptor)是在Web开发中常用的机制,比如对 HTTP Request 进行日志,对包含资源进行用户认证和权限检查等。 Verxt Web 中没有明确的提前拦截器的概念(Interceptor), 但我们可以通过路由(Router)轻松的模拟该行为。
基本原理
在 Vertx 中,虽然没有原生的提供拦截器(Interceptor)的概念或软件实体。但提供了链式调用路由 (Router) 的能力,我们只需要在 URL 上设计好层级关系,并通过在 Router 中调用 next() 方法,就可以完成对下一个 Router 的调用。如:
1 | router.route("/api/v1/*").handler(ctx -> { |
案例实操
本文采用在 Vertx 构建Rest服务实验手册(一) 系列文章中构建的例中,你只需要跟随到系列文章的第三篇即可。
在案例中,我们定义以下上个URL:
/api/v1 - 所有 URL 的前缀部分
/api/v1/auth - 需要用户认证以后才能访问的部分
/api/v1/auth/todo - 简单的获取待办事项的 API, 模拟在真实系统中的需要用户认证的业务API
加入第一级路由
首先我们加入一个路由 (Router), 该路由模拟记录所有的访问信息, 代码如下:
1 | router.route("/api/v1/*").handler(ctx -> { |
可以看到,所有以 “/api/v1/“ 开头的访问都会被该路由处理,在处理中,我们调用了 next() 方法,以便将当前 request 传递给下一个路由 (Router)。
加入第二级路由
代码如下:
1 | router.route("/api/v1/auth/*").handler(ctx -> { |
可以看到,我们在上面代码中只是简单的记录了日志,在实际的场景中,可以使用 ctx.responses.end() 来终止无权限的访问。
修改业务API的URL
最后,我们修改访问 Todo API 的URL。 修改后的代码如下:
1 | router.route("/api/v1/auth/todo").handler(ctx -> { |
可以看到,我们将 Todo API 放置到了 /api/vi/auth 的下一级。
现在,可以运行案例, 然后在浏览器中访问
1 | http://localhost:8080/api/v1/auth/todo |
可以在浏览器中看到结果:
1 | {"succ":true,"code":null,"msg":null,"data":{"id":1,"title":"call tom","desc":"description"}} |
查看后台的日志输出,可以看到:
1 | log start... |
说明第一个和第二个路由 (Router) 被调用了,效果和在其它框架中的拦截器(Interceptor) 或 Filter 是一样的。
路由平级的情况
如果两个路由器 (Router) 不是构成层级关系,而是平级关系,对路由器的执行顺序有什么影响呢?
比如我们把上面例中第二个路由器的代码改为:
1 | router.route("/api/v1/*").handler(ctx -> { |
会有什么结果呢? 如果你运行程序,会发现结果不变,其实 vertx 会根据你注册每个路由器的顺序来觉得先、后关系。