使用 Plug 验证特定端点的 headers

Validating headers for specific endpoints with Plug

背景

我有一个简单的 Plug 路由器,它有一些 POST、PUT 和 GET 端点。但是,每个端点都需要对请求的 header 进行特定的验证。我不知道如何用 Plug 实现这一点。 代码

我有一个非常通用的路由器,它接收请求并将它们重定向到控制器:

defmodule Api do
  use Plug.Router

  alias Api.Controllers.{Product, NotFound, Ping}

  plug :match
  plug Plug.Logger
  plug :dispatch

  get "/ping",  do: Ping.process(conn)
  put "/product",    do: Product.process(conn)

  match _, do: NotFound.process(conn)
end

问题

但是,少了一步。我需要 /products 端点来验证 headers。也就是说,headers 应该设置一些特定的字段,例如,像“conten-type”header 甚至是自定义的 header,如“bananas”。

此验证不适用于所有端点。更糟糕的是,每个端点都会进行自己的验证,例如,拥有“bananas”header 可能对“/products”端点很重要,但“/ping”端点并不关心.

研究

我已阅读这篇文章:

但是,这适用于所有端点,并不具体。

问题

您可以在 do 块中为插件中的路径做任何您想做的事情。我有时会使用环绕过滤模式来处理这样的事情。类似于:

defmodule Api do
  use Plug.Router

  # ...

  put "/product"  do
    with_valid_headers(conn, fn ->
      Product.process(conn)
    end)
  end

  defp with_valid_headers(conn, action) do
    if get_req_header(conn, "banana") == "Cavendish" do
      action.()
    else
      send_resp(conn, 400, "Invalid banana")
    end
  end

  # ...
end

当然,如果不打算重复使用此验证,则可以将其放在do 块的主体中​​。