我已经看过几个例子,你从那里读r.Body
,然后r.Body.Close()
马上做一个延迟。如果我们不关闭它会发生什么?
假设我有一个http.Handler
,在里面我像这样解码 r.Body 的内容:
func createFeedback(w http.ResponseWriter, r *http.Request) {
// ... Some code ...
f := feedback.New()
if err := json.NewDecoder(r.Body).Decode(f); err != nil {
return err
}
defer r.Body.Close()
// ... Some more code ...
}
Run Code Online (Sandbox Code Playgroud)
为什么我们要关闭r.Body
?
我只是在读取/proc/diskstats
文件。我的代码是:
func ReadFromFile(filepath string)(string){
defer func() {
if err1 := recover(); err1 != nil {
fmt.Println("!!!!!!!!!!!!!!!!Panic Occured and Recovered in readFromFile(), Error Info: ", err1)
}
}()
strData := ""
data, err := ioutil.ReadFile(filepath)
if err != nil{
fmt.Println("File read error: ", err)
return ""
}
strData = string(data)
return strData
}
Run Code Online (Sandbox Code Playgroud)
我得到的错误是:
File read error: open /proc/diskstats: too many open files
Run Code Online (Sandbox Code Playgroud)
不仅对于此文件,对于其他一些文件,我也遇到相同的错误。
我还运行了以下命令:
root@golang:~# lsof|wc -l
785
Run Code Online (Sandbox Code Playgroud)
请指导我。
我的程序从一台服务器下载一个文件,然后将其返回给用户。这是它的片段:
// Make get request to target server
resp, httpErr := http.Get(url.String())
// Return error if http request is failed
if httpErr != nil {
fmt.Fprintln(w,"Http Request Failed :" ,httpErr.Error())
return
}
//Setting up headers
w.Header().Set("Content-Disposition", "attachment; filename="+vid.Title+"."+format.Extension)
w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
w.Header().Set("Content-Length", strconv.Itoa(int(resp.ContentLength)))
// Copy instream of resp.Body to writer
io.Copy(w, resp.Body)
Run Code Online (Sandbox Code Playgroud)
当用户停止下载或关闭连接时,我也想关闭 GET 连接。但正如我通过使用图发现的那样,它并没有关闭。如何关闭用户的连接?
我有以下代码:
resp, err = http.Head("http:something.com")
if err != nil {
//do something
}
if resp.StatusCode == http.StatusOK {
// do something
}
Run Code Online (Sandbox Code Playgroud)
由于我没有阅读 的正文,因此resp
我假设我不需要像 那样关闭它resp.Body.Close()
。我的假设正确吗还是我应该打电话resp.Body.Close()
?
在这篇文章中,指出应该关闭 response.Body 以避免资源泄漏。它也显示在http 包 godoc中的概述示例中。
在我的测试代码中,我发送了多个请求来尝试一个 API
resp, err := http.DefaultClient.Do(req)
在同一个函数中多次。这是一种不好的做法吗?在这种情况下,我是defer resp.Body.Close()
在每个人之后写,还是只写一次?
url := server.URL + "/ticket/add"
reader = strings.NewReader(`{"id": "test1", "detail": "test1"}`)
req, err := http.NewRequest("POST", url, reader)
assert.Nil(t, err)
resp, err := http.DefaultClient.Do(req)
assert.Nil(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusCreated, resp.StatusCode)
// add a ticket with same id
reader = strings.NewReader(`{"id": "test1"}`)
req, err = http.NewRequest("POST", url, reader)
assert.Nil(t, err)
resp, err = http.DefaultClient.Do(req)
assert.Nil(t, err)
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
Run Code Online (Sandbox Code Playgroud)
一个相关的问题,在服务器端,即在 内部func(w …
我正在提出请求,但不需要回复。如果我这样做会产生任何问题吗?
client = &http.Client{
Timeout: time.Duration(15 * time.Second),
}
...
...
_, err := client.Do(req)
Run Code Online (Sandbox Code Playgroud) 请参阅此处的示例https://pkg.go.dev/net/http#example-Get。下面也有截图:
func main() {
res, err := http.Get("http://www.google.com/robots.txt")
if err != nil {
log.Fatal(err)
}
body, err := io.ReadAll(res.Body)
res.Body.Close() // Why!?
if res.StatusCode > 299 {
log.Fatalf("Response failed with status code: %d and\nbody: %s\n", res.StatusCode, body)
}
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", body)
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:为什么我需要关闭res.Body.Close()
第7行。我没有打开它。我在如果我不关闭response.Body会发生什么?中看到了解释。我明白文档是这么说的。
有没有更好的方法来解决这个问题?
我认为这违反了开闭原则。我认为如果 ReadAll 打开了 steam,它应该将其关闭。Go 中通常是这样完成这些事情的吗?