Elixir 如何在Phoenix框架中运行响应后中间件功能?

Elixir 如何在Phoenix框架中运行响应后中间件功能?,elixir,phoenix,plug,Elixir,Phoenix,Plug,我正在开发一个简单的网站在长生不老药与凤凰城。我想添加一些在生成响应后运行的自定义中间件。例如,为了记录每个响应中的总字节数,我希望有这样一个插件 defmodule HelloWeb.Plugs.ByteLogger do import Plug.Conn require Logger def init(default), do: default def call(conn, default) do log("bytes sent: #{String.le

我正在开发一个简单的网站在长生不老药与凤凰城。我想添加一些在生成响应后运行的自定义中间件。例如,为了记录每个响应中的总字节数,我希望有这样一个插件

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管道中使用此插件将无法工作,它们都是在响应呈现之前运行的。相反,它会导致
函数子句错误
,因为
conn.resp_body
nil
。我不知道如何使用此插件,以便在呈现响应后运行。

我想您正在寻找

这允许注册在
resp_body
设置为nil as之前调用的回调

应该是这样的:

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\u body
    不一定是字符串,可以是I/O列表
  • byte\u size/1
    应用于计数字节,
    String.length/1
    返回UTF-8字形计数
以下内容可以完成这项工作,但由于需要连接主体,因此会对性能产生重大影响:

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

似乎工作得很好,我想性能会更好。

谢谢!我切换到
IO.iodata\u length(conn.resp\u body)
来设置响应大小,它似乎工作得很好,我不知道
IO.iodata\u length/1
。显然,它在引擎盖下是完全相同的(
&IO.iodata_length/1
的计算结果是
&:erlang.iolist_size/1
,因为它是内联的),但使用起来感觉更好。直到,谢谢!