提供用於定義路由的Shelf中間件。java
shelf_route是一個功能強大的路由器,能夠輕鬆地以模塊化方式定義路由。api
shelf_route旨在:服務器
這使它很是通用,讓您能夠將它與其餘最喜歡的Shelf中間件組件混合搭配。架構
Shelf世界中有多種路由選擇。 這是一個簡單的指南,能夠幫助您選擇其中一些。框架
簡而言之,若是你想構建本身的堆棧,那麼shelf_route和shelf_rest可能會更適合你。 若是你想要一個功能更全面的框架,同時仍然具備高度可擴展性,那麼mojito是更好的選擇。curl
要更好地瞭解您擁有的選項,請閱讀博客文章中的路由選項。模塊化
使用router函數建立路由器函數
var myRouter = router();
使用路由器的get方法使用GET Http方法添加路由post
myRouter.get('/', (_) => new Response.ok("Hello World");
使用路由器的handler屬性獲取Shelf Handlerfetch
var handler = myRouter.handler;
如今,您可使用Shelf IO提供路由
io.serve(handler, 'localhost', 8080);
因此完整的hello world看起來像
import 'package:shelf/shelf.dart'; import 'package:shelf/shelf_io.dart' as io; import 'package:shelf_route/shelf_route.dart'; void main() { var myRouter = router() ..get('/', (_) => new Response.ok("Hello World")); io.serve(myRouter.handler, 'localhost', 8080); }
它支持全部標準的http方法
myRouter..get('/', (_) => new Response.ok("Hello World")) ..post('/', (_) => new Response.ok("Hello World")) ..put('/', (_) => new Response.ok("Hello World")) ..delete('/', (_) => new Response.ok("Hello World"));
您可使用add指定多個方法
myRouter.add('/', ['GET', 'PUT'], (_) => new Response.ok("Hello World"));
shelf Router使用UriPattern定義每條路線的匹配路徑。 這意味着只要實現此接口,您就可使用您喜歡的路徑的任何格式。
默認狀況下,它使用UriTemplate,它實現了同名的強大標準。
UriTemplate容許綁定到:
它使用{parameter name}表示法來表示路徑參數
myRouter.get('/{name}', (request) => new Response.ok("Hello ${getPathParameter(request, 'name')}"));
路徑參數經過Shelf Path的getPathParameter函數獲取。
一樣,您也能夠綁定到查詢參數
myRouter.get('/{name}{?age}', myHandler); myHandler(request) { var name = getPathParameter(request, 'name'); var age = getPathParameter(request, 'age'); return new Response.ok("Hello $name of age $age"); }
爲了提升模塊性,您能夠將路由分解爲一系列嵌套路由。
您可使用addAll方法添加子路由。
例如,您能夠爲以/ banking開頭的全部路由添加子路由器
var rootRouter = router()..addAll((Router r) => r ..addAll((Router r) => r ..get('/', fetchAccountHandler) ..post('/deposit', makeDepositHandler), path: '/account/{accountNumber}'), path: '/banking');
而後經過rootRouter提供全部路由
io.serve(rootRouter.handler, 'localhost', 8080)
請注意,在這種狀況下,deposit資源的完整路徑其實是
/banking/account/{accountNumber}/deposit
要試一試,請啓動服務器並執行此操做
curl -d 'lots of money' http://localhost:8080/banking/account/1235/deposit
您能夠將其餘中間件添加到各個路由
myRouter.get('/', (_) => new Response.ok("Hello World"), middleware: logRequests());
此中間件將應用於該路由上的全部請求。
若是將其添加到子路由器,它將應用於該路由器的全部路由
var bankingRouter = rootRouter.addAll((Router r) {...}, path: '/banking', middleware: logRequests()),
將適用於全部banking路由和'/ banking'的全部子路由。
路由器的addAll方法採用相似的typedef
typedef RouteableFunction(Router router);
藉助Dart函數模擬能力,這意味着您能夠輕鬆地將一組路由組合在一塊兒。
class MyGroup { void call(Router router) { router..get('/', (_) => new Response.ok("Hello World")) ..get('/greeting/{name}', (request) => new Response.ok("Hello ${getPathParameter(request, 'name')}")); } }
爲了使它更加明確,你能夠擴展Routeable類,它只是讓你調用createRoutes方法而不是調用。
既然你如今有了一個類,你也能夠將處理程序分解爲方法
class MyGroup extends Routeable { void createRoutes(Router router) { router..get('/', helloWorld) ..get('/greeting/{name}', greeting); } Response helloWorld(request) => new Response.ok("Hello World")) Response greeting(request) => new Response.ok("Hello ${getPathParameter(request, 'name')}")); }
而後將其添加到另外一臺路由
rootRouter.addAll(new MyGroup());
使用printRoutes函數很容易看到爲路由定義的全部路由。
var router = r.router() ..get('/', (_) => new Response.ok("Hello World")) ..post('/', (_) => new Response.ok("Hello World")) ..get('/greeting/{name}{?age}', (request) { var name = getPathParameter(request, 'name'); var age = getPathParameter(request, 'age'); return new Response.ok("Hello $name of age $age"); }); printRoutes(router);
prints
GET -> / POST -> / GET -> /greeting/{name}{?age}
查看項目源下示例文件夾中的更多詳細示例。
本節介紹基本的自定義。
這些是定製路由工做方式的有效方法,而且能夠處理大多數自定義shelf_route的狀況。
若是您須要更多,請參閱下面有關擴展的部分
全部路由器方法的路徑參數都接受:
默認狀況下,String值將被解析爲UriParser,這意味着它應符合UriTemplate。
您也能夠實現本身的UriPattern並使用它。 例如,您可能更喜歡:路徑變量的樣式(例如:name)。
此外,它容許您建立uri路徑定義,並可能在客戶端和服務器之間共享。 例如
var accountPattern = new UriParser(new UriTemplate('/account/{accountNumber}'));
您如今能夠在定義路徑和客戶端時使用此功能。
myRouter.get(accountPattern, (_) => new Reponse.ok("Hello World"));
爲了更加無縫地使用您本身的路徑樣式,您能夠在路由中安裝路徑適配器。 這將由此路由器中的全部路由和任何子路由器使用,除非您在某處覆蓋它。
經過將適配器傳遞給Router函數來安裝適配器。
var colonStyleAdapter = ....; // obtain the adapter from somewhere var myRouter = router(pathAdapter: colonStyleAdapter);
如今您可使用冒號樣式路徑參數
myRouter.get('/:name', (request) => new Response.ok("Hello ${getPathParameter(request, 'name')}"));
您能夠安裝自定義處理程序適配器,它容許您轉換傳遞給路由器方法的處理程序。 這容許與其餘Shelf包更加無縫集成。
例如,若是您想使用普通的Dart函數做爲處理程序,您可使用像Shelf Bind這樣的包。 Shelf Bind提供開箱即用的這種適配器。
經過將適配器傳遞給路由函數來安裝適配器。
import 'package:shelf_bind/shelf_bind.dart' as bind; var myRouter = router(handlerAdapter: bind.handlerAdapter())
如今你能夠作到
myRouter.get('/{name}', (name) => "Hello ${name}");
代替
myRouter..get('/{name}', (request) => new Response.ok("Hello ${getPathParameter(request, 'name')}"));
注意,若是沒有安裝適配器,您仍然能夠直接調用Shelf Bind的bind方法。
myRouter.get('/{name}', bind((name) => "Hello ${name}"));
注意:包含shelf_bind的最簡單方法是使用shelf_rest而不是shelf_route
相似於HandlerAdapter如何容許您無縫集成提供替代形式的處理程序(如Shelf Bind)的程序包,RouteableAdapter容許您無縫集成支持RouteableFunction的替表明示的程序包。
RouteableFunction和RouteableAdapter定義以下
typedef RouteableFunction(Router router); typedef RouteableFunction RouteableAdapter(Function handler);
您能夠在建立頂級路由器時安裝適配器
var myRouteableAdapter = // create some how var myRouter = router(routeableAdapter: myRouteableAdapter)
如今你能夠作到
myRouter.addAll(new MyResource(), path: 'mine');
將調用myRouteableAdapter以使MyResource的實例適應RouteableFunction
注意:與全部適配器同樣,您能夠在路由樹的任何級別安裝它們,它們將從該點開始生效。 例如
myRouter.addAll(new MyResource(), path: 'mine', routeableAdapter: myRouteableAdapter);
若是您沒法使用上述技術實現自定義,那麼您來對地方了。 但首先要了解一下shelf_route的架構。
shelf_route分爲兩個主要部分:
對應於運行時路由組件,是一對更抽象的模型。 這些對是路徑的抽象表示,稱爲路徑規範,以及負責從給定路徑規範建立相應路徑組件的適配器。 更具體地說,有:
請注意這些模型是故意很是抽象的,以支持最大的靈活性。可是,在幾乎全部狀況下,您更有可能處理提供更具體實現的DefaultRouterAdapter等子類。提供中間件和調整路由路徑的支持方式(例如支持不一樣的路徑樣式,如':foo')和處理程序(例如shelf_bind提供的容許普通Dart函數用做shelf處理程序的方式)
shelf_route的最高級擴展形式一般在此級別工做,但生成規範和適配器,其中一個或兩個多是自定義子類。
請注意,適配器從父路由繼承屬性。 所以,一般沒必要在路由樹中的每一個節點處提供適配器。 樹頂部的單個可能就足夠了。
SpecBasedRouterBuilder,也是路由器規範,具備將這些規範添加到構建器的方法,例如addRoute
目前,瞭解如何擴展shelf_route的最佳位置是shelf_rest的源代碼。
有關全部選項的更多詳細信息,請參閱Wiki
查看未解決的問題