我正在用 Elixir 和 Phoenix 开发一个简单的网站。我想添加一些在生成响应后运行的自定义中间件。例如,为了记录每个响应中的字节总数,我想要一个像这样的插头
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_body
为 nil
。我不知道如何使用这个插件,以便它可以在响应呈现后运行。
最佳答案
我认为您正在寻找 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 列表byte_size/1
应用于计算字节数,String.length/1
返回 UTF-8 字素计数
以下内容可以完成这项工作,但由于需要连接正文,会对性能产生重大影响:
conn.resp_body |> to_string() |> byte_size()
:erlang.iolist_size/1似乎运行良好,我认为性能方面要好得多。
关于elixir - 如何在 Phoenix 框架中运行响应后的中间件函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63478471/