2

我有一个将请求转发到其他路由器的路由器模块。在这个路由器中,我有一个由plug(:match)和组成的管道plug(:dispatch)

defmodule Example.Router do
  use Plug.Router

  plug(:match)
  plug(:dispatch)

  forward("/check", to: Example.Route.Check)

  get("/", do: send_resp(conn, 200, "router"))
end

在第二个模块中,我有相同的管道:

defmodule Example.Route.Check do
  use Plug.Router

  plug(:match)
  plug(:dispatch)

  get "/", do: send_resp(conn, 200, "ok")
end

我在这里看到的问题是我似乎总是需要plug(:match)并且plug(:dispatch)在所有Plug路由器中。所以我有以下问题:

  1. 这真的有必要吗?
  2. 是否所有路由器都需要在具有路由的同一文件中具有管道?
4

2 回答 2

6

是的,始终需要两个插头:

  • :match插件负责将传入请求与路由器中定义的路由之一进行匹配。

  • :dispatch插件负责最终处理匹配路由中的请求。


这里明显的问题是:

为什么不自动执行它,因为这需要为每个请求完成?

  1. 对于初学者来说,这是因为显式地做事而不是隐式地做事。

  2. 其次,更重要的是,插件按照定义的顺序执行。这使开发人员可以完全控制传入请求的处理方式。


例如,您可能希望Authorization在匹配路由之前检查标头并从那里停止或继续请求。或者,您可能希望在一个单独的过程中更新网页浏览计数,一旦匹配路由但在处理之前。另一个常见的场景是在路由匹配解析 JSON 请求。

您可以通过自定义管道来完成所有这些以及更多操作:

defmodule Example.Router do
  use Plug.Router

  plug(CheckRateLimit)
  plug(VerifyAuthHeader)
  plug(:match)
  plug(LogWebRequest)
  plug(Plug.Parsers, parsers: [:json], ...)
  plug(:dispatch)

  # ...
end

将匹配的路由转发到其他路由器的能力可以使您的 Web 服务器更加复杂。例如,您可以检查基本路由器中的 API 速率限制,将路由转发/admin到单独的路由,并在匹配这些路由之前AuthorizedRouter将自定义插件放在那里。VerifyAuthHeader

于 2018-11-22T11:46:59.643 回答
2

虽然@Sheharyar 的答案是绝对正确的,但我要补充一点,您可以通过引入自己的辅助宏来干燥:

defmodule Example.Route.Common do
  defmacro __using__(opts \\ []) do
    quote do
      use Plug.Router

      plug(:match)
      plug(:dispatch)
    end
  end
end

并像这样使用它:

defmodule Example.Route.Check do
  use Example.Route.Common

  get "/", do: send_resp(conn, 200, "ok")
end

opts参数可用于精细配置包含的插件。

Kernel.use/2.

于 2018-11-22T12:41:16.557 回答