如何在Phoenix框架中运行响应后的中间件功能? [英] How do you run middleware functions post response in Phoenix framework?

查看:92
本文介绍了如何在Phoenix框架中运行响应后的中间件功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在与Phoenix一起在Elixir中开发一个简单的网站.我想添加一些自定义中间件,该中间件在生成响应后 即可运行.例如,为了记录每个响应中的字节总数,我想要一个这样的插件

I'm developing a simple website in Elixir with Phoenix. I'd like to add some custom middleware that runs after a response has been generated. For example, in order to log the total number of bytes in each response I'd like to have a Plug like this

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 .我不确定如何使用此插件,以便在响应呈现后即可运行.

Trying to use this plug in one of the Phoenix pipelines in the router won't work though, they are all run before the response is rendered. Instead it causes a FunctionClauseError since conn.resp_body is nil. I'm not sure how to use this plug so it can run after the response is rendered.

推荐答案

我认为您正在寻找 register_before_send/2 .

这允许注册在 resp_body 设置为nil之前将被调用的回调,例如

This allows to register callbacks that will be called before resp_body gets set to nil as 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 作为字节大小:

I don't think you should be using String.length for the byte size:

  • resp_body 不一定是字符串,可以是I/O列表
  • byte_size/1 用于计数字节, String.length/1 返回UTF-8字素计数
  • resp_body is not necessarily a string, can be an I/O-list
  • byte_size/1 should be used to count bytes, String.length/1 returns UTF-8 grapheme count

以下方法可以完成这项工作,但是由于需要连接身体,因此会对性能产生重大影响:

The following could do the job, but with a significant performance impact due to the need of concatenating the body:

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

:erlang.iolist_size/1 似乎运行良好,我认为在性能方面要好得多.

:erlang.iolist_size/1 seems to work well and I suppose is much better performance-wise.

这篇关于如何在Phoenix框架中运行响应后的中间件功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆