一个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
.
限制大小:
过大则413 -Request Entity Too Large
表单属性合并
文件上传:
router.route().handler(BodyHandler.create());
router.post("/some/path/uploads").handler(routingContext ->{
Set<FileUpload> uploads = routingContext.fileUploads();
// Do something with uploads....
});
支持cookies处理
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