需求
读取 http 请求中的大数据, 每次读取一定的体积.
Plug.Conn.read_body/2
@spec read_body(t(), Keyword.t()) ::
{:ok, binary(), t()} | {:more, binary(), t()} | {:error, term()}
此函数有三个配置选项, 根据文档, length:
表示这一次函数调用读取数据的长度; read_length:
表示从底层的 socket 每次读取数据的长度; read_timeout:
表示从底层的 socket 每次读的 timeout.
测试
看起来很不错, 但其实只能起到一个大概的作用, 不能相信它返回的数据一定小于某个大小.
我们对不同的配置选项进行测试:
# defp print_size(body, config), do:
# IO.inspect({byte_size(body), config})
body = :binary.copy("abcdefghij", 100_000)
assert {:more, body, conn} = read_body(conn, length: 0, read_length: 1_000)
print_size(body, {0, 1000})
assert {:more, body, conn} = read_body(conn, length: 5_000, read_length: 1_000)
print_size(body, {5000, 1000})
assert {:more, body, conn} = read_body(conn, length: 20_000, read_length: 1_000)
print_size(body, {20_000, 1000})
assert {:ok, body, conn} = read_body(conn, length: 2_000_000)
print_size(body, {2_000_000, nil})
第一次结果:
{2766, {0, 1000}}
{5840, {5000, 1000}}
{20440, {20000, 1000}}
{970954, {2000000, nil}}
第二次结果:
{2766, {0, 1000}}
{8760, {5000, 1000}}
{21900, {20000, 1000}}
{966574, {2000000, nil}}
注意到每次读取到的数额都会比我们设置的 length 大, 甚至大于 length + read_length. 所以这个配置是不可靠的, 如果想要精确地按长度处理 body 内的数据, 还是需要进行进一步的分割操作.