需求

读取 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 内的数据, 还是需要进行进一步的分割操作.


Ljzn
399 声望102 粉丝

网络安全;函数式编程;数字货币;人工智能