cURL 缓冲对下载流式数据的影响
之前用 cURL 访问一个 gRPC 的流式(Stream)接口(已转换成 HTTP)时,出现了一个非常奇怪的现象:
- 当直接
cuRL
时,总是能显示完整的内容,并且连接不会断开,因为是流式接口,完全符合预期的行为; - 而当
cURL | ...
或cURL > file
时,始终得不到完整的内容,而且无论等多久都不行;
这是为什么呢?这个问题困扰了我很长一段时间。直到昨天灵机一现突然想到了原因:
大概率是因为 cURL 的 缓冲(buffer) 导致的。
于是读了 cURL 的 manual,还真的有一个是跟 buffer 相关的:
1 2 3 4 5 6 7 |
|
然后尝试开启,果然问题解决。
但是,仍然有一个问题没有解决,为什么直接 cURL
的时候总是能显示完整的内容?不应该也 buffer 起来吗?未找到答案。盲猜是版本原因。
我写了一小段代码来尝试复现这个问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
注:加 Transfer-Encoding
的原因是 go 语言默认会 chunked 传输,也不知道怎么简单关闭。
由于 cURL 的 缓冲(Buffer) 大小是 16KB,于是我的代码中构造了 16KB 多一点点数据。
现在来尝试请求这个接口:
1 2 3 4 |
|
果然停在了这里,后面的 456789 没有了。只要代码里面 sleep 得够久,这里就会一直等。
但是灵异的是,无论我是重定向到文件,还是通过管道给其它命令,都未能完全复现上面的问题(我懒得写 grpc 例子了)。
另外,cURL 可以指定在多长时间内如果速度持续低于某个值,则停止下载(返回错误码 28:Operation timeout):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
我前面提到的服务是一个流式订阅服务,启动时会订阅全量,后续订阅到增量数据(较少),所以订阅完一般就会速度变为零, 这对于我来说,这几个参数变得很好使。最终我的命令如下:
1 2 3 |
|
至于最开始的问题:输出到终端行,到文件或管道就不行的问题,仍无答案。