你如何 运行 中间件函数 post 在 Phoenix 框架中响应?

How do you run middleware functions post response in Phoenix framework?

我正在使用 Phoenix 在 Elixir 中开发一个简单的网站。我想添加一些自定义中间件,运行s after 已生成响应。例如,为了记录每个响应中的总字节数,我想要一个这样的插件

defmodule HelloWeb.Plugs.ByteLogger do
  import Plug.Conn
  require Logger

  def init(default), do: default

  def call(conn, default) do
    log("bytes sent: #{String.length(conn.resp_body)}")
  end
end

尽管尝试在路由器的 Phoenix 管道之一中使用此插件是行不通的,但在呈现响应之前它们都是 运行。相反,它会导致 FunctionClauseError,因为 conn.resp_bodynil。我不确定如何使用此插件,以便在呈现响应后可以 运行。

我想你正在寻找 register_before_send/2

这允许注册将在 resp_body 设置为 nil 之前调用的回调,因为 explained here

应该看起来像:

defmodule HelloWeb.Plugs.ByteLogger do
  import Plug.Conn
  require Logger

  def init(default), do: default

  def call(conn, default) do
    register_before_send(conn, fn conn ->
      log("bytes sent: #{String.length(conn.resp_body)}")

      conn
    end)
  end
end

编辑:我认为您不应该使用 String.length 作为字节大小:

  • resp_body不一定是字符串,可以是一个I/O-list
  • byte_size/1应该用字节计数,String.length/1returnsUTF-8字素计数

以下内容可以完成这项工作,但由于需要连接正文,因此会对性能产生重大影响:

conn.resp_body |> to_string() |> byte_size()

:erlang.iolist_size/1 似乎运作良好,我想更好 performance-wise.