Vert.x之旅(二):Route

一个Route对象可以包含零个或多个Route;

一个Route处理一个HTTP请求,找到第一个匹配请求路径,并传递参数给它。

该Route在接收请求后有关联的程序处理,可以处理、结束,或者传递给下一个匹配的程序处理。

举例:

HttpServer server = vertx.createHttpServer();
 
Router router =Router.router(vertx);
 
router.route().handler(routingContext ->{
 
 // This handler will be called for every request
 HttpServerResponse response = routingContext.response();
 response.putHeader("content-type","text/plain");
 
 // Write to the response and end it
 response.end("Hello World from Vert.x-Web!");
});
 
server.requestHandler(router::accept).listen(8080);

 

 

RoutingContext

代表请求处理的上下文

提供了访问HttpServerRequest和HttpServerResponse

路由到处理程序会被丢弃

 

处理请求,并调用下一个请求:

Route route1 = router.route("/some/path/").handler(routingContext ->{
 
 HttpServerResponse response = routingContext.response();
 // enable chunked responses because we will be adding data as
 // we execute over other handlers. This is only required once and
 // only if several handlers do output.
 response.setChunked(true);
 
 response.write("route1\n");
 
 // Call the next matching route after a 5 second delay
 routingContext.vertx().setTimer(5000, tid -> routingContext.next());
});
 
Route route2 = router.route("/some/path/").handler(routingContext ->{
 
 HttpServerResponse response = routingContext.response();
 response.write("route2\n");
 
 // Call the next matching route after a 5 second delay
 routingContext.vertx().setTimer(5000, tid ->  routingContext.next());
});
 
Route route3 = router.route("/some/path/").handler(routingContext ->{
 
 HttpServerResponse response = routingContext.response();
 response.write("route3");
 
 // Now end the response
 routingContext.response().end();
});

 

阻塞处理

router.route().blockingHandler(routingContext ->{
 
 // Do something that might take some time synchronously
 service.doSomethingThatBlocks();
 
 // Now call the next handler
 routingContext.next();
 
});

路由路径头

Route route = router.route().path("/some/path/*");
 
route.handler(routingContext ->{
 // This handler will be called for any path that starts with
 // `/some/path/`, e.g.
 
 // `/some/path`
 // `/some/path/`
 // `/some/path/subdir`
 // `/some/path/subdir/blah.html`
 //
 // but not:
 // `/some/bath`
});

捕获参数

/catalogue/products/tools/drill123/

Route route = router.route(HttpMethod.POST,"/catalogue/products/:productype/:productid/");
 
route.handler(routingContext ->{
 
 String productType = routingContext.request().getParam("producttype");
 String productID = routingContext.request().getParam("productid");
 
 // Do something with them...
});

HTTP方法路由

router.get().handler(routingContext ->{
 
 // Will be called for any GET request
 
});
 
router.get("/some/path/").handler(routingContext ->{
 
 // Will be called for any GET request to a path
 // starting with /some/path
 
});
 
router.getWithRegex(".*foo").handler(routingContext ->{
 
 // Will be called for any GET request to a path
 // ending with `foo`
 
});
 
Route route = router.route().method(HttpMethod.POST).method(HttpMethod.PUT);
 
route.handler(routingContext ->{
 
 // This handler will be called for any POST or PUT request
 
});

 

路由顺序

默认为增加顺序,顺序从0开始,order方法设置顺序

Route route1 = router.route("/some/path/").handler(routingContext ->{
 
 HttpServerResponse response = routingContext.response();
 // enable chunked responses because we will be adding data as
 // we execute over other handlers. This is only required once and
 // only if several handlers do output.
 response.setChunked(true);
 
 response.write("route1\n");
 
 // Now call the next matching route
 routingContext.next();
});
 
Route route2 = router.route("/some/path/").handler(routingContext ->{
 
 HttpServerResponse response = routingContext.response();
 response.write("route2\n");
 
 // Now call the next matching route
 routingContext.next();
});
 
Route route3 = router.route("/some/path/").handler(routingContext ->{
 
 HttpServerResponse response = routingContext.response();
 response.write("route3");
 
 // Now end the response
 routingContext.response().end();

});

// Change the order of route2 so it runs before route1

route2.order(-1);

route1
route2
route3

 

基于MIME类型描述请求路由

使用comsumes

router.route().consumes("text/html").consumes("text/plain").handler(routingContext ->{
 
 // This handler will be called for any request with
 // content-type header set to `text/html` or `text/plain`.
 
});
 
router.route().consumes("text/*").handler(routingContext ->{
 
 // This handler will be called for any request with top level type `text`
 // e.g. content-type header set to `text/html` or `text/plain` will both match
 
});
 
router.route().consumes("*/json").handler(routingContext ->{
 
 // This handler will be called for any request with sub-type json
 // e.g. content-type header set to `text/json` or `application/json` will both match
 
});

 

基于MIME类型描述客户端可接受的路由

配置content-type

router.route().produces("application/json").handler(routingContext ->{
 
 HttpServerResponse response = routingContext.response();
 response.putHeader("content-type","application/json");
 response.write(someJSON).end();
 
});
 
router.route().produces("application/json").produces("text/html").handler(routingContext ->{
 
 HttpServerResponse response = routingContext.response();
 
 // Get the actual MIME type acceptable
 String acceptableContentType = routingContext.getAcceptableContentType();
 
 response.putHeader("content-type", acceptableContentType);
 response.write(whatever).end();
});

 

上下文数据

routingContext包含所有处理请求生命周期中的所有数据。

使用routingContext.data访问数据图

router.get("/some/path").handler(routingContext ->{
 
 routingContext.put("foo","bar");
 routingContext.next();
 
});
 
router.get("/some/path/other").handler(routingContext ->{
 
 String bar = routingContext.get("foo");

 // Do something with bar
 routingContext.response().end();
 
});

 

重路由

reroute

router.get("/some/path").handler(routingContext ->{
 
 routingContext.put("foo","bar");
 routingContext.next();
 
});
 
router.get("/some/path/B").handler(routingContext ->{
 routingContext.response().end();
});
 
router.get("/some/path").handler(routingContext ->{
 routingContext.reroute("/some/path/B");
});

 

子路由

/products/product1234

 

Router restAPI =Router.router(vertx);
restAPI.get("/products/:productID").handler(rc ->{
 // TODO Handle the lookup of the product....
 rc.response().write(productJSON);
});
restAPI.put("/products/:productID").handler(rc ->{
 // TODO Add a new product...
 rc.response().end();
});
restAPI.delete("/products/:productID").handler(rc ->{
 // TODO delete the product...
 rc.response().end();
});
 
Router mainRouter =Router.router(vertx);
 
// Handle static resources
mainRouter.route("/static/*").handler(myStaticHandler);
 
mainRouter.route(".*\\.templ").handler(myTemplateHandler);
 
mainRouter.mountSubRouter("/productsAPI", restAPI);

国际化

解析Accept-Language头部使用acceptableLocales方法

locale不存在,preferredLocale回第一个元素

Route route = router.get("/localized").handler( rc ->{
 // although it might seem strange by running a loop with a switch we
 // make sure that the locale order of preference is preserved when
 // replying in the users language.
 for(Locale locale : rc.acceptableLocales()){
   switch(locale.language()){
     case"en":
       rc.response().end("Hello!");
       return;
     case"fr":
       rc.response().end("Bonjour!");
       return;
     case"pt":
       rc.response().end("Olá!");
       return;
     case"es":
       rc.response().end("Hola!");
       return;
   }
 }
 // we do not know the user language so lets just inform that back:
 rc.response().end("Sorry we don't speak: "+ rc.preferredLocale());
});

 

默认404路由

路由不存在

 

错误处理

抛出异常或者指定http错误代码会被failureHandler捕获,

如果程序捕获了异常,不会被捕获,会抛出500错误代码。

Route route1 = router.get("/somepath/path1/");
 
route1.handler(routingContext ->{
 
 // Let's say this throws a RuntimeException
 thrownewRuntimeException("something happened!");
 
});
 
Route route2 = router.get("/somepath/path2");
 
route2.handler(routingContext ->{
 
 // This one deliberately fails the request passing in the status code
 // E.g. 403 - Forbidden
 routingContext.fail(403);
 
});
 
// Define a failure handler
// This will get called for any failures in the above handlers
Route route3 = router.get("/somepath/*");
 
route3.failureHandler(failureRoutingContext ->{
 
 int statusCode = failureRoutingContext.statusCode();
 
 // Status code will be 500 for the RuntimeException or 403 for the other failure
 HttpServerResponse response = failureRoutingContext.response();
 response.setStatusCode(statusCode).end("Sorry! Not today");
 
});

请求体处理

BodyHandler允许获取请求体,限制大小,处理文件上传

router.route().handler(BodyHandler.create());
获取请求体:

getBodyAsJson,getBodyAsString,getBody.

限制大小:

setBodyLimit

过大则413 -Request Entity Too Large

表单属性合并

setMergeFormAttributes.

文件上传:

router.route().handler(BodyHandler.create());
 
router.post("/some/path/uploads").handler(routingContext ->{
 
 Set<FileUpload> uploads = routingContext.fileUploads();
 // Do something with uploads....
 
});

支持cookies处理

使用CookieHandler.

router.route().handler(CookieHandler.create());

操纵cookies

router.route().handler(CookieHandler.create());
 
router.route("some/path/").handler(routingContext ->{
 
 Cookie someCookie = routingContext.getCookie("mycookie");
 String cookieValue = someCookie.getValue();
 
 // Do something with cookie...
 
 // Add a cookie - this will get written back in the response automatically
 routingContext.addCookie(Cookie.cookie("othercookie","somevalue"));
});
 

处理sessions

猜你喜欢

转载自zzqfsy.iteye.com/blog/2288511