elixir - 如何在 Phoenix 框架中运行响应后的中间件函数?

标签 elixir phoenix-framework plug

我正在用 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_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 列表
  • 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/

相关文章:

elixir - Phoenix 附加布局变量,例如 @inner

angularjs - 在 Phoenix/Elixir 中启用跨域资源共享 CORS

file-upload - 在 Elixir 中使用 Acr 将文件上传到本地

elixir - 如何将请求参数填充到 Plug.Conn 连接中?

elixir - 加入 Phoenix Channel(或其他 pubsub)时同步应用程序状态

elixir - 无法在 Phoenix umbrella 应用程序中加载 Assets

elixir - 自定义 ExUnit 断言和模式匹配

npm - 不要将所有 css 文件编译成 app.css 并在需要时手动包含其中一些

javascript - 在 Elixir Phoenix 1.3 应用程序的 .vue 文件中使用扩展运算符时出现语法错误

phoenix-framework - 在插件模块中使用 Controller 和 Conn 功能的最佳方式是什么?