我正在寻找一种方法,在Cowboy中,将任意路径(存储在数据库中)映射到特定的博客帖子。
那就是:我有几千篇博文,可以通过几个名称访问,例如规范网址(例如/post/42
),一些别名(例如/2013/11/25/erlang-rocks
),历史位置(例如/path-on-old-blog/12345
)等
我知道我可以简单地使用全能路线:
{ "/[...]", catch_all_handler, [] },
...然后查找数据库中的路径,但我正在考虑从数据库创建路由,如下所示:
Posts = posts:all(),
Paths = [get_handlers_for_post(P) || P <- Posts],
Routes = lists:flatten(Paths),
get_handler_for_post(P) ->
% Generate a list of paths with IDs from the database.
% Return something that looks like this:
% [{"/canonical/1", post_handler, [1]},
% {"/first-alias", post_handler, [1]}].
% TODO: code goes here...
即:将所有可能的路径放在路由器中,指向同一个处理程序,每个路径都有帖子的ID。
问题是:这是明智的吗?牛仔支持多少条路线?
答案 0 :(得分:3)
你可以做到,但没有必要。牛仔在路由中具有非常有效的模式匹配语法。让我们以你的例子中给出的路线为例
[{"/canonical/1", post_handler, [1]},
{"/first-alias", post_handler, [1]}].
第一个网址有一个额外的路径是可选的。在牛仔中,您可以将这两条路线表示为
"/:first/[:second]"
这匹配/canonical/1
以及/first-alias
第一个和第二个都是参数化的,它们可以取任何值。 :second
周围的方括号表示这是可选的。上述模式将匹配您提供的两个路径。
那么你如何在路由处理程序中实际访问这些参数呢?
真的很简单。 Cowboy在cowboy_req模块中提供了一个绑定方法,您可以从那里访问您的网址参数
cowboy_req:binding(first,Req)
如果是您的第一个网址,则会返回{<<"canonical">>,Req}
。
请注意,参数是atom
。使用参数和可选参数,您应该能够匹配整个网址集。
详细了解路由here
更多解释
据我了解,您有数千个不同的博客帖子,而且他们的网址不一致。我建议而不是创建路由动态地找到一致url的模式并将它们分组到路由中。回落在牛仔中自动发生。如果它在模式上不匹配,它会看向另一个,依此类推。
例如
\:a\:b
将匹配
\hello\man
,hello\world
,\hello\slash\
与hello\man\world
不匹配。
\:a\:b\[:c]
将匹配\hello\man
,hello\world
,hello\man\world
路线数量没有硬性限制。你可以拥有你需要的任意数量。
答案 1 :(得分:0)
很久以前问的,还是很有趣。
不,我不认为生成的 Cowboy 路由规则是在大量非结构化路径上进行查找的有效方法。
cowboy_router:compile/1
生成的调度规则是元组、列表和二进制的结构,如下所示:
[{'_',[],
[{[<<"canonical">>,<<"1">>],[],post_handler,[1]},
{[<<"first-alias">>],[],post_handler,[1]}]}]
路由是这种结构中的线性搜索。它会被复制到每个请求处理程序进程中,因此如果它非常大,则每个请求的复制都会产生很大的开销。
在 Cowboy 的最新版本中,路线可以存储在 persistent_term
中,从而消除了复制。尽管如此,它仍然是一个线性搜索。
对于大量非结构化路径,我相信 ETS 表查找会更有效,因为它是作为哈希表实现的。
我想提到的另一个选项,因为您正在考虑代码生成,是生成一个 Erlang 模块,其中包含一个执行查找的函数。这消除了复制,并且可以从模式匹配的编译器优化中受益。
%% Generated module
-module(blog_path_aliases).
-export([lookup/1]).
lookup(<<"/2013/11/25/erlang-rocks">>) -> 42;
lookup(<<"/path-on-old-blog/12345">>) -> 42;
lookup(<<"/some-other/path">>) -> 123;
...