使用Elixir和Hackney将数据作为流读取

时间:2015-12-08 07:22:50

标签: elixir

我正在使用hackney,我正在尝试使用here中的说明将请求的正文作为流阅读。 由于代码是用Erlang编写的,我必须使它适应在Elixir中工作:

yylex()

我用它来运行:

  def read_body(max_length, client, acc) when max_length > byte_size(acc) do
    case :hackney.stream_body(client) do
      {:ok, data} -> read_body(max_length, client, acc <> data)
      :done -> {:ok, acc}
      {:error, reason} -> {:error, reason}
    end
  end

  def read_body(max_length, client, acc) do
    acc
  end

问题是我希望使用上面的代码只读取身体的前20个字节的数据,但acc = HackneyTutorial.read_body(20, client, "") # I have my own methods for retrieving the client 变量获取整个身体,它要么不考虑护卫{ {1}},或只是在第一次调用acc时读取所有正文。

您认为可以解决这个问题?

1 个答案:

答案 0 :(得分:1)

您的read_body/3功能正在发生以下两件事之一:

  1. 正如您所提到的,整个正在从:hackney.stream_body/1调用中返回,该调用恰好大于max_length,这会导致调用read_body/3的第二个定义
  2. 正在返回正文的部分,因为read_body/3递归执行,直到acc的大小不再小于max_length,然后导致read_body/3的第二个定义被调用(结果与1相同)。
  3. 基于:hackney.stream_body/1read_body/3函数和max_length后卫 acc大于指定max_length的两种情况下,:done案例(或{:error, reason}案例)都不会匹配。

    为了限制返回的正文的大小,一种解决方案是在case表达式中添加两个额外的守卫,并在没有守卫的情况下删除read_body/3的辅助定义:

    def read_body(max_length, ref, acc) do
      case :hackney.stream_body(ref) do
        {:ok, _} when byte_size(acc) > max_length ->
          read_body(max_length, ref, acc)
        {:ok, data} when (byte_size(data) + byte_size(acc)) > max_length ->
          read_body(max_length, ref, acc <> String.slice(data, 0, max_length - byte_size(acc)))
        {:ok, data} ->
          read_body(max_length, ref, acc <> data)
        :done ->
          {:ok, acc}
        {:error, reason} ->
          {:error, reason}
      end
    end
    

    另一种解决方案可能是从max_length中减去返回数据的大小,直到达到0,然后忽略其余数据:

    def read_body(0, ref, acc) do
      case :hackney.stream_body(ref) do
        {:ok, _} ->
          read_body(0, ref, acc)
        :done ->
          {:ok, acc}
        {:error, reason} ->
          {:error, reason}
      end
    end
    def read_body(max_length, ref, acc) do
      case :hackney.stream_body(ref) do
        {:ok, << data :: binary-size(max_length), _ :: binary >>} ->
          read_body(0, ref, acc <> data)
        {:ok, data} ->
          read_body(max_length - byte_size(data), ref, acc <> data)
        :done ->
          {:ok, acc}
        {:error, reason} ->
          {:error, reason}
      end
    end
    

    两种解决方案都有相同的结果,但显示了几种解决同一问题的不同方法。