Golang Go语言中 http.Get 是阻塞的吗 还是说有超时呢 求问

发布于 1周前 作者 yibo5220 来自 Go语言

Golang Go语言中 http.Get 是阻塞的吗 还是说有超时呢 求问

func justRun(userinfo userInfo) bool {
r, _ := http.Get(“http://localhost:8080/?imeicode=” + userinfo.ImeiCode)
var w []byte
if r != nil {
w, _ = ioutil.ReadAll(r.Body)
_ = r.Body.Close()
} else {
time.Sleep(5 * time.Second)
if r != nil {
w, _ = ioutil.ReadAll(r.Body)
_ = r.Body.Close()
} else {
r, _ := http.Get(“http://localhost:8080/?imeicode=” + userinfo.ImeiCode)
time.Sleep(5 * time.Second)
if r != nil {
w, _ = ioutil.ReadAll(r.Body)
_ = r.Body.Close()
}
}
}
if len(w) == 4 {
return true
} else {
return false
}
}

看了源码发现 Get 调用的 NewRequest 方法
但是小白表示没发现什么异常呀 晕了
这个 get 请求的地址是同服务器的 代码如下

func handle(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	_ = r.ParseForm()
	if runCode(r.Form["imeicode"][0]) {
		_, _ = Fprint(w, "true")
	} else {
		_, _ = Fprint(w, "false")
	}
}

runCode 的执行时间大概在 1s 以内 不会超过 2 秒
返回值也是 bool 型
还有一直没搞懂的是 r.Body.Close()这个到底是干啥用的
因为服务端调用这个之后 朝着 w 写东西 客户端也能收到
客户端调用这个之后 貌似什么都不会发生?


更多关于Golang Go语言中 http.Get 是阻塞的吗 还是说有超时呢 求问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

21 回复

为啥我的代码会写的这么丑呢…
求解答

更多关于Golang Go语言中 http.Get 是阻塞的吗 还是说有超时呢 求问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


是同步阻塞的,r.Body 必须显式的 close 掉,不然,不断有请求,但资源没释放,程序很快会崩掉的。你上面那段代码问题很多,首先要检察 err,而不是去判断 r 是否是 nil。还有没有关闭 r.Body

哦,看错了,有 close,还是看 golang 标准库中的例子吧,挺别扭的

好好利用 error 啊,少用 else 多用提前 return.

也就是说 http.Get 这个方法不会异步执行是吗
检查了 err 是 connect time out … 这个超时是哪里规定的呢
他不会一直等待我的服务端 r.Body.Close()吗
我在想这个要不要改成 RPC 会不会好一点呢

我觉得最好玩的就是 如果没有响应(r == nil)的话
我再延时 5s 居然就能读取了
所以我就有一种 Get 是异步执行的错觉
而且服务端的那段代码理论上不会执行很久
就很奇怪

http.Get 对于调用者来说自然是同步阻塞的,对于失败的请求,你自然不需要去调用 r.Body.Close,标准库已经帮你做了,timeout 是因为标准库内部使用了 context,控制了某一次请求的生命周期,http.Get 其实是使用了 DefaultClient, 如果需要自己设置这个超时时间,你需要设置 client 的 Timeout 属性。多看源码吧。

好的 谢谢!🙏

您好,我想请问一下,如果我在一个 for 循环中调用 http.Get (不使用 goroutine ),这些 http 请求是会逐个执行,还是并发执行呢?

我觉得当然是逐个执行呀 想想 for 循环里随便一个表达式 只要不加 go 都是执行完上一条才下一条

无法回答楼主的问题,但是顺道提一下,最好不要这么写

<br> if r != nil {<br> w, _ = ioutil.ReadAll(r.Body)<br> _ = r.Body.Close()<br> } else {<br> time.Sleep(5 * time.Second)<br> if r != nil {<br> w, _ = ioutil.ReadAll(r.Body)<br> _ = r.Body.Close()<br> } else {<br> r, _ := http.Get("http://localhost:8080/?imeicode=" + userinfo.ImeiCode)<br> time.Sleep(5 * time.Second)<br> if r != nil {<br> w, _ = ioutil.ReadAll(r.Body)<br> _ = r.Body.Close()<br> }<br> }<br> }<br>

而是这样写

<br> if r == nil {<br> w, _ = ioutil.ReadAll(r.Body)<br> _ = r.Body.Close()<br> return false<br> } <br><br> // 正确情况的逻辑<br><br>}<br>

也就是说,尽量不要用 if-else 的方式处理错误,在 if 中处理错误即可。具体可以参考 effective go。
还有就是,重试最好也别写在错误处理里,万一你要重试 10 次咋办?

…v2ex 不能使用 markdown 回复吗?

按理来说是这样,但上次我朋友跟我说 http.Get 在内部自带 goroutine 机制。我验证一下吧。

谢谢! 我在试着用 RPC 重新写这一段代码 实在太丑了 而且 http 的超时我也没找到在哪…尴尬

内部自带这个是指的服务端吧? 我觉得客户端没必要啊 并发打服务器玩吗?

是的我验证了一下,的确是顺序执行的 = =

server 端的 request 不需要自己 close

是这样, 如果我想关闭这个链接该怎么办呢. 比如用户填写表单错误的时候要让代码不要向下执行, 谢谢.

额,return 就可以了

在Golang(Go语言)中,http.Get 函数是阻塞的,它发起一个 HTTP GET 请求并等待服务器响应。默认情况下,http.Get 并没有设置超时时间,这意味着如果服务器没有响应或者网络延迟很高,http.Get 会一直等待下去,直到服务器响应或连接失败(比如由于网络问题)。

为了在使用 http.Get 时避免潜在的阻塞问题,你可以使用 http.Client 并设置超时时间。以下是一个示例代码,展示了如何为 HTTP 请求设置超时:

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

func main() {
	client := &http.Client{
		Timeout: 10 * time.Second, // 设置超时时间为10秒
	}

	resp, err := client.Get("http://example.com")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return
	}

	fmt.Println(string(body))
}

在这个例子中,我们创建了一个 http.Client 实例,并设置了 Timeout 字段为10秒。这样,如果请求在10秒内没有得到响应,client.Get 会返回一个错误。这种方式可以有效地避免由于网络延迟或服务器无响应导致的阻塞问题。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!