提供用于定义路由的Shelf中间件。
shelf_route是一个功能强大的路由器,可以轻松地以模块化方式定义路由。
shelf_route旨在:
这使它非常通用,让您可以将它与其他最喜欢的Shelf中间件组件混合搭配。
Shelf世界中有多种路由选择。 这是一个简单的指南,可以帮助您选择其中一些。
简而言之,如果你想构建自己的堆栈,那么shelf_route和shelf_rest可能会更适合你。 如果你想要一个功能更全面的框架,同时仍然具有高度可扩展性,那么mojito是更好的选择。
要更好地了解您拥有的选项,请阅读博客文章中的路由选项。
使用router函数创建路由器
var myRouter = router();
使用路由器的get方法使用GET Http方法添加路由
myRouter.get('/', (_) => new Response.ok("Hello World");
使用路由器的handler属性获取Shelf Handler
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
查看未解决的问题