1
BBCCBB 333 天前
response 和 body 是不同的资源吧, java 里 body 是 inputStream. 拿到后也是要 close 的. body close 后, response 依然可以用.
body close 只代表你把响应里的 body 读取完了.. 但 response 里还有其他信息可以继续读的, cookie, header |
2
tyrantZhao 333 天前 via iPhone
读一个 body 肯定要关,跟 http 没啥关系。
|
3
mainjzb 333 天前 1
老忘记的话,可以自己封装一层 http 请求。
不这么设计的话,chunked 编码下容易遇到问题。 |
4
777777 333 天前
有 timeout 自动会帮你关
|
5
guanzhangzhang 333 天前
|
6
mainjzb 333 天前
楼主可能没有视频开发的经验
以 b 站直播为例,打开 F12 可以发现 bilivideo.com 的请求在一直拉数据。如果客户端发生错误,可以调用 body close()主动关闭请求。例如检测到长时间无人操作关闭连接节约流量。 或者检测到浏览器缩小化,关闭画面,只拉声音,降低服务器负载。 |
7
Mohanson 333 天前
哈哈, 看了这个帖子发现前几天写的一段代码忘记关闭 Body 了
|
8
AoEiuV020JP 333 天前
高级一点的现代语言都有封装一些方便的方法,比如直接把 body 完整读取转成字符串并 close ,但 go 给人感觉就是现代语言却要对标上古 c/c++,这种细节小麻烦在 c/c++就是理所当然没什么不合理,
|
9
flyv2x 333 天前
确实因为没有 close 的问题,压测发现 bug 找了一下午,火大
|
10
zihuyishi OP @tyrantZhao go 的问题在于你不读这个 body 也要 close ,然后很多时候不读就忘记了 close 。所以普通的请求都要自己套一层实现
|
11
zihuyishi OP @777777 golang 里不会关吧,而且他这个 body 你不读他也要关。他底层还关系到了很多 goroutine,所以经常 pprof 跑一下发现一堆 goroutine 在那里持续了几天
|
12
lvlongxiang199 333 天前
@AoEiuV020JP 如果是个文件呢 ? 直接读到内存里, 没准会 OOM
|
13
DefoliationM 333 天前
不然自动关了全读内存里存着?不合理呀。
|
14
mainjzb 333 天前
理论上确实应该设计成 close response ,和文件 api 统一风格更合理。
但是短期来看没希望了。response 已经有一个 Colse 变量了。无法再创建 Close 方法。 |
15
sujin190 333 天前 via Android
body 是流式传输吧,有最大缓冲区,超过了就不会继续下载读取
|
16
GooMS 333 天前 via Android
我觉得要关闭更好,好控制
|
17
seers 333 天前
已经习惯性 defer 了,还好
|
18
jinliming2 333 天前 via iPhone
@AoEiuV020JP #8 能流式操作的不建议完整读取,还转字符串。性能会差,内存会炸。
除非预先知道 body 大小足够小,或者是无法流式处理操作。 |
19
jim9606 333 天前 via Android
go 没有 using 语法糖,所以还是 defer 吧,我看 open 之后马上 defer close 还挺常见的。
|
20
flyqie 333 天前 via Android
其实,主要是 go 不太甜的原因。。
|
21
pluto1 332 天前 via iPhone
作为一个官方库肯定是要考虑到所有场景的,就像上面说的视频,或者还有很多需要不断读取的场景。
至于 Close 哪个的话这个就另说了,我个人感觉 Close body 好像合理一点。 顺便提醒下楼上的,defer 前一定要检查 body 是不是 nil ,不然如果 body 出现 nil 的情况,defer 执行的时候我记得是会 panic 的 |
22
lvlongxiang199 332 天前
我觉得很合理. `resp.Body` 就是个 reader 跟 fileReader 类似, 区别就是这是别人帮你 open 然后把 ownership move 给你, 负责 close 是用户的事, 你觉得 fileReader 必须 close 是不是合理的 ?
虽然对于大部分调用 rest api 的情况, 是把 reader 内的读出来, 之后 close. 但是对于需要流式获取的场景并不合适(比如: 实时视频流, 大文件), 按我的理解, 进入标准库的东西, 得适配普遍的场景, 而非 rest api 这种单一场景 |
23
crackidz 332 天前
语法糖也是要关闭的,只是不需要你手工关闭而已。response 对象的话包含了很多的其他内容,即使允许 close response 也能读取其中的其他信息,这其实很反直觉的。
|
24
holulu 332 天前
觉得不合理就换个语言吧,没必要纠结这些问题,不同的语言设计就不一样,要么自己设计一种符合自己习惯的。
|
25
kingofzihua 332 天前
用 CI 工具,golangci-lint 支持检测 bodyclose
|
26
CodeCodeStudy 332 天前
所以就要用到框架啊,让框架来处理这些底层的、琐碎的事情
|
27
maigebaoer 332 天前 via Android
我也遇到过这个坑😅😅😅
|
28
gamexg 332 天前
@pluto1 #21
看文档,至少官方实现 Body 不会出现 nil 的情况. 我一直没检查过 body 是否为 nil Body represents the response body. The response body is streamed on demand as the Body field is read. If the network connection fails or the server terminates the response, Body.Read calls return an error. The http Client and Transport guarantee that Body is always non-nil, even on responses without a body or responses with a zero-length body. It is the caller's responsibility to close Body. The default HTTP client's Transport may not reuse HTTP/1.x "keep-alive" TCP connections if the Body is not read to completion and closed. |
29
6diyipi 332 天前
文档就不看,出了问题逼逼赖赖。 官方库功能又不是为了满足你一个人, 想偷懒用 https://github.com/go-resty/resty
|
30
gamexg 332 天前
我是习惯了,
经常手写 net.Dial ,Close 是接着就会跟着的. 其实我感觉应该是标准库为了提供足够的灵活性, 按 golang 语言逻辑,如果不提供关闭,那么基本就只能内部实现 io.ReadAll ,那么意味着超大/超长延迟的响应会占用很大内存/很长时间.对于一些情况会有很大的影响. 例如我读取一个很长的 api 响应,是直接对着 body 这个流进行解析,而不是全部读取到内存再处理. |
31
AoEiuV020JP 332 天前
@jinliming2 #18 图的是方便,具体用不用肯定是需要开发者自己斟酌的,
比如,上手学习测试, 请求 json api ,网页下载解析,都可能可以用, 性能表现之类肯定比不过流处理,但高级语言服务场景也不是时时刻刻都要扣这一点点性能,所以我说这种细节坑在 c/c++没有不合理,但放在现代语言就显得不合群了, |
32
AoEiuV020JP 332 天前
@lvlongxiang199 #12 没有哪个高级语言是不提供流读取的, 没有人会把二进制大文件转字符串读到内存里的,
别给你个糖你就不吃饭了,饿死了怪别人给你糖, |
33
lvlongxiang199 332 天前
@AoEiuV020JP
> 高级一点的现代语言都有封装一些方便的方法,比如直接把 body 完整读取转成字符串并 close 我的意思是, 这种封装挪到第三方库就行了, 没必要放到标准库, 这东西的使用场景很有限. 流式读取的应用场景更广泛, []byte, string 都可以看作是流 ps: **请你好好说话** |
34
lvlongxiang199 332 天前
@AoEiuV020JP 我仅仅说你提供的这个封装不适合处理这种情况, 没说 golang 没提供这种处理. io.Reader 就是一个流
|
35
iseki 332 天前 via Android
Go 标准库很多 API 设计得都比较有特色。抛开 Go 不谈对于 HTTP 库一个典型设计是 response / body 都有独立的 close ,response 的关闭会导致 body 被连带关闭。
|
36
AoEiuV020JP 332 天前
@lvlongxiang199 #33 我想说的就是你这种站在 c/c++视角想问题的,落后几十年了,
要说不必须,那连 http 整个都不是必须的,都可以移到第三方库,你觉得是为什么 go 要自带 http 功能, 现代语言提供必要功能之外的服务是很正常的事,毕竟现代每一个编程语言的出现都是为了解决已有语言的痛点,那就必定会提供不必要但是方便的东西, 这方面 go 就感觉不上不下的,关键总有人把 go 拉到 c/c++这边把各种不方便合理化, 我的观点是,go 如果哪天想开了加上这类不必要的方法也是理所当然的, |
37
AoEiuV020JP 332 天前
@lvlongxiang199 #33 在我这里,反问=阴阳怪气=不好好说话,
|
38
AoEiuV020JP 332 天前
@lvlongxiang199 #34 我的意思就是糖不需要管饱,这种封装方法不需要解决所有情况,有就可以了,能用的时候可以提供方便就可以了, 不需要管不适用的情况,
|
39
Nazz 332 天前
http 协议里面内容很多, 不要只考虑 json api
|
40
xfriday 332 天前
GC 类语言没有析构导致的,GC 只能回收内存,其他资源只能手动销毁
|
41
ihciah 332 天前
从设计上主要原因是 http 协议和客户端是两阶段读的。Response 读完 header 就可以返回,body 可以读或者不读。读不读也会影响连接管理,所以无论如何都需要一个显式关闭能力。
至于为啥要手动关,那是语言本身问题,还是没析构函数/drop 的原因。 |
42
thynson 332 天前
没有 RAII 的语言可不是要手动关闭嘛。
|
43
hotsymbol 332 天前
赶紧换 Rust ,Go 一堆历史遗留问题。只能平替 Python ,这些 web server 还是得交给 rust 和 Java
|
44
lasuar 331 天前
go 的 net 库算是 low-level ,需要暴露这个方法。
|
45
avrilko 331 天前
rust 适合你
|
47
sampeng 329 天前
也没啥问题吧。。。新手?踩 1-2 次雷不就知道了。。
|