vlambda博客
学习文章列表

Vert.x - vertx-web 路由讲解总结


一、vertx-web

上篇文章我们对 vertx 进行了简单的介绍,并使用 vertx-web 实践了 restFul 接口的书写,本篇文章接着上篇继续讲解 vertx-web 的路由。

对于环境的搭建请参考上篇文章的内容。

二、vertx-web 路由

1. 精确匹配

精确路径是日常开发中常用的方式,精确匹配到某个接口。

router.get("/test1").handler(ctx -> { ctx.response().end("success");});

2. 路径前缀的匹配

有的时候可能需要匹配以某某为开头的请求,此时可以使用路径前缀的路由,在vertx 中可以使用 * 代表路径,如:

router.get("/test/*").handler(ctx -> { String url = ctx.request().absoluteURI(); ctx.response().end(url+"--> success");});

Vert.x - vertx-web 路由讲解总结还可以通过这种方式还可以对接口进行拦截或处理:

router.get("/test/*").handler(ctx -> { String url = ctx.request().absoluteURI(); if (Objects.isNull(ctx.request().getParam("p"))){ ctx.response().end("参数为空!"); return; } ctx.next();});router.get("/test/abc").handler(ctx -> { String url = ctx.request().absoluteURI(); ctx.response().end(url+"--> success2");});

上面以/test开头的必须要携带 p 参数:Vert.x - vertx-web 路由讲解总结Vert.x - vertx-web 路由讲解总结

3. 获取路径上的参数

在 SpringMVC 中我们可以通过 @PathVariable 获取路径上的参数,在 vertx 中同样也是可以的,可以使用 :参数名 的方式,如:

router.get("/pathParam/:name/:age").handler(ctx -> { String name = ctx.pathParam("name"); String age = ctx.pathParam("age"); ctx.response().end(name+" "+age);});

Vert.x - vertx-web 路由讲解总结

4. 使用正则表达式进行匹配

前面有使用 * 的方式来匹配任意后缀的请求,但使用正则的话可以满足基本任何规则的匹配,在 vertx 正则的方法都带有WithRegexVert.x - vertx-web 路由讲解总结基本上常用的请求方式都支持正则,如匹配abc结尾的后缀:

router.getWithRegex(".*abc").handler(ctx->{ String url = ctx.request().absoluteURI(); ctx.response().end(url + "--> success");});

Vert.x - vertx-web 路由讲解总结

5. 路由顺序

上面路径前缀的匹配说到可以利用这个进行请求的拦截,其实就是使用的 vertx 中的路由顺序,在 vertx 中,声明同一个 url 不会进行覆盖而是都会加载到该 url 请求的列表中,默认进入第一个请求,可以通过 ctx.next() 执行下一个,如:

router.get("/shunxu").handler(ctx -> { if (Objects.isNull(ctx.request().getParam("p"))) { ctx.response().end("没有传递参数!"); } else { ctx.next(); }});router.get("/shunxu").handler(ctx -> { ctx.response().end("参数: " + ctx.request().getParam("p"));});

Vert.x - vertx-web 路由讲解总结Vert.x - vertx-web 路由讲解总结

6. 限制请求的MIME类型

有时候我们的接口可能只想接收 Content-Type=application/json的请求,其他的都不接收,可以通过 consumes 进行限制,并且在 vertx 中还提供了ctx.is 可以用来判断请求的类型是否属于某一类:如:

router.get("/mime") .consumes("application/json") .handler(ctx -> { String header = ctx.request().getHeader("Content-Type"); boolean b = ctx.is("application/json"); boolean b1 = ctx.is("application/json;charset=UTF-8"); boolean b2 = ctx.is("text/json"); ctx.response().putHeader("Content-Type","text/html").end(header + " , " + b + " , " + b1 + " , " + b2); });

Vert.x - vertx-web 路由讲解总结Vert.x - vertx-web 路由讲解总结Vert.x - vertx-web 路由讲解总结可以看出限制是包含关系。

7. VirtualHost 限制

有些情况我们的接口可能只允许某个 host 的请求,此时就可以使用 VirtualHost ,如限制为127.0.0.1 则使用 localhost 则访问不同 :

router.get("/virtualHost").virtualHost("127.0.0.1").handler(ctx->{ String url = ctx.request().absoluteURI(); ctx.response().end(url + "--> success");});

Vert.x - vertx-web 路由讲解总结Vert.x - vertx-web 路由讲解总结

8. 上下文数据传递

在上面说请求顺序的时候,涉及到多个 请求handler , 而多个 handler 之间也是可以传递数据的,可以通过 ctx.put 进行:

router.get("/put").handler(ctx->{ String p = ctx.request().getParam("p"); ctx.put("p",p+"123"); ctx.next();}).handler(ctx->{ Optional.ofNullable(ctx.get("p")).map(String::valueOf).ifPresent(p->{ ctx.response().end(p); });});

Vert.x - vertx-web 路由讲解总结

9. 重定向

在vertx 中直接使用 ctx.redirect 即可实现重定向,如:重定向到百度:

router.get("/redirect").handler(ctx -> { ctx.redirect("http://www.baidu.com");});

Vert.x - vertx-web 路由讲解总结

重定向到内部其他接口:

router.get("/redirect").handler(ctx -> { ctx.redirect("/test");});

10. 返回JSON

在 vertx 中返回 json ,可以直接使用提供的 ctx.json 即可,传入一个 JsonObject

router.get("/getJson").handler(ctx -> { JsonObject jsonObject = new JsonObject().put("code", "200").put("message", "success"); ctx.json(jsonObject);});

Vert.x - vertx-web 路由讲解总结

11. 失败处理

在逻辑执行时,如果遇到异常此时没有捕获的话就会返回 500 ,对此 vertx 提供了 failureHandler ,来捕获异常,有点类似于服务的降级,failureHandler 可以全局捕获也可以针对某个请求:

router.get("/err").handler(ctx -> { int a = 1 / 0;}).failureHandler(ctx -> { ctx.response().end("请求异常:" + ctx.failure().getMessage());});

Vert.x - vertx-web 路由讲解总结全局捕获:

router.route().failureHandler(ctx->{ ctx.response().end("请求异常:" + ctx.failure().getMessage());});
router.get("/err").handler(ctx -> { int a = 1 / 0;});

12. 文件上传

vertx 的文件上传已经帮我们做了简化,直接使用BodyHandler进行处理即可,文件默认放在当前的 file-uploads 下,并且为了防止重名,存在该目录下的并不是我们上传的文件名,而是 UUID,到我们自己的 handler 中只需使用 ctx.fileUploads 即可获取到上传的文件信息。

注意点:本篇文章采用的 vertx 版本为 4.1.8 ,如果整合 SpringBoot ,需要使用 2.2.X的版本,如果是 2.3.X 上传文件会卡住,解决办法是使用 vertx 4.2.x 的版本在 SpringBoot 2.3.X 是正常的。

router.post("/fileupload") .handler(BodyHandler.create() .setHandleFileUploads(true) .setBodyLimit(5*1024*1024) .setPreallocateBodyBuffer(true)) .handler(ctx -> { Set<FileUpload> set = ctx.fileUploads(); System.out.println("上传文件数:"+set.size()); if (set.isEmpty()) { ctx.response().end("文件为空!"); return; } set.forEach(f -> { System.out.println("name: "+f.name()); System.out.println("fileName: "+f.fileName()); System.out.println("uploadedFileName: "+f.uploadedFileName()); }); ctx.response().end("success"); });

Vert.x - vertx-web 路由讲解总结Vert.x - vertx-web 路由讲解总结下面是上传到服务的文件:Vert.x - vertx-web 路由讲解总结

13. 静态资源

Vertx 带有开箱即用的 StaticHandler 实例处理静态资源,用于处理静态Web资源,默认静态文件目录为 webroot。

router.route("/static/*").handler(StaticHandler.create());

Vert.x - vertx-web 路由讲解总结Vert.x - vertx-web 路由讲解总结

14. 允许跨域

Vertx 中跨域也有开箱即用的 CorsHandler,首先写一个普通接口:

router.get("/cors").handler(ctx -> { ctx.response().end("success");});

使用 ajax 调用上面的接口:

$.ajax({ url: "http://localhost:8090/cors", type: "get", success: function (result) { console.log(result) }});

浏览器请求:出现了跨域的错误,下面添加跨域的允许:

router.route().handler(CorsHandler.create() .addOrigin("*") .allowedHeader(" x-www-form-urlencoded, Content-Type,x-requested-with") .allowedMethod(HttpMethod.GET) .allowedMethod(HttpMethod.POST) .allowedMethod(HttpMethod.PUT) .allowedMethod(HttpMethod.DELETE));

再次刷新页面: