我正在使用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
时读取所有正文。
您认为可以解决这个问题?
答案 0 :(得分:1)
您的read_body/3
功能正在发生以下两件事之一:
:hackney.stream_body/1
调用中返回,该调用恰好大于max_length
,这会导致调用read_body/3
的第二个定义read_body/3
递归执行,直到acc
的大小不再小于max_length
,然后导致read_body/3
的第二个定义被调用(结果与1相同)。基于:hackney.stream_body/1
,read_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
两种解决方案都有相同的结果,但显示了几种解决同一问题的不同方法。