如何读取HTTP分块响应并在Elixir中向客户端发送分块响应?

Jes*_*ieh 2 proxy logging elixir chunked-encoding phoenix-framework

我正在使用Elixir/Phoenix,我有一个端点,它返回一个分块响应,比如说一个永无止境的日志行流.但是,日志行来自另一个服务A,它也返回一个分块响应.我希望我的端点从服务A读取分块响应,并以块的形式将它们传递给客户端.从本质上讲,它只是服务A的代理,但我不能让客户端直接连接到服务A,因为我需要执行一些身份验证.

sto*_*ack 5

以下是与Phoenix发送块数据的示例:

  def test_1(conn, _params) do
    conn = conn
    |> put_resp_content_type("text/event-stream")
    |> send_chunked(200)

    conn |> chunk("a")
    conn |> chunk("b")
    conn |> chunk("c")

    # send data five times, once per second, to simulate a log
    for n <- 1..5 do
      conn |> chunk(Integer.to_string(n))
      Process.sleep(1000)
    end

    conn
  end
Run Code Online (Sandbox Code Playgroud)

Elixir/Erlang有一些http库可用; 我很喜欢HTTPoison.

这是一个从URL读取块的示例,并在它们进入时将它们发送出去:

  def test_2(conn, _params) do
    url = "http://localhost:4000/test_1"
    %HTTPoison.AsyncResponse{id: id} = HTTPoison.get!(url, %{}, stream_to: self())

    conn = conn
    |> put_resp_content_type("text/event-stream")
    |> send_chunked(200)

    process_httpoison_chunks(conn, id)
  end

  def process_httpoison_chunks(conn, id) do
    receive do
      %HTTPoison.AsyncStatus{id: ^id} ->
        # TODO handle status
        process_httpoison_chunks(conn, id)
      %HTTPoison.AsyncHeaders{id: ^id, headers: %{"Connection" => "keep-alive"}} ->
        # TODO handle headers
        process_httpoison_chunks(conn, id)
      %HTTPoison.AsyncChunk{id: ^id, chunk: chunk_data} ->
        conn |> chunk(chunk_data)
        process_httpoison_chunks(conn, id)
      %HTTPoison.AsyncEnd{id: ^id} ->
        conn
    end
  end
Run Code Online (Sandbox Code Playgroud)

一些参考:

  • 我刚刚实现了这一点,但是注意到当我在5秒左右没有收到另一个块时连接被丢弃了.你碰巧知道一种保持tcp连接存活的方法吗? (2认同)
  • @JesseShieh啊,是的,`HTTPoison`的`recv_timeout`选项默认为'5000`ms.你可以把它设置成大的,或者`:infinity`.类似于:`HTTPoison.get!(url,%{},stream_to:self(),recv_timeout :: infinity) (2认同)