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 写东西 客户端也能收到
客户端调用这个之后 貌似什么都不会发生?
1
Licsber OP 为啥我的代码会写的这么丑呢..
求解答 |
2
yufpga 2018-12-08 19:59:16 +08:00 via Android
是同步阻塞的,r.Body 必须显式的 close 掉,不然,不断有请求,但资源没释放,程序很快会崩掉的。你上面那段代码问题很多,首先要检察 err,而不是去判断 r 是否是 nil。还有没有关闭 r.Body
|
3
yufpga 2018-12-08 20:01:41 +08:00 via Android
哦,看错了,有 close,还是看 golang 标准库中的例子吧,挺别扭的
|
4
mengyaoss77 2018-12-08 20:05:19 +08:00 via Android
好好利用 error 啊,少用 else 多用提前 return.
|
5
Licsber OP @yufpga 也就是说 http.Get 这个方法不会异步执行是吗
检查了 err 是 connect time out .. 这个超时是哪里规定的呢 他不会一直等待我的服务端 r.Body.Close()吗 我在想这个要不要改成 RPC 会不会好一点呢 |
6
Licsber OP @mengyaoss77 我觉得最好玩的就是 如果没有响应(r == nil)的话
我再延时 5s 居然就能读取了 所以我就有一种 Get 是异步执行的错觉 而且服务端的那段代码理论上不会执行很久 就很奇怪 |
7
yufpga 2018-12-08 20:26:30 +08:00 via Android
http.Get 对于调用者来说自然是同步阻塞的,对于失败的请求,你自然不需要去调用 r.Body.Close,标准库已经帮你做了,timeout 是因为标准库内部使用了 context,控制了某一次请求的生命周期,http.Get 其实是使用了 DefaultClient, 如果需要自己设置这个超时时间,你需要设置 client 的 Timeout 属性。多看源码吧。
|
9
azzwacb9001 2018-12-08 22:12:26 +08:00
@yufpga 您好,我想请问一下,如果我在一个 for 循环中调用 http.Get (不使用 goroutine ),这些 http 请求是会逐个执行,还是并发执行呢?
|
10
Licsber OP @azzwacb9001 我觉得当然是逐个执行呀 想想 for 循环里随便一个表达式 只要不加 go 都是执行完上一条才下一条
|
11
azzwacb9001 2018-12-08 22:19:33 +08:00
无法回答楼主的问题,但是顺道提一下,最好不要这么写
``` 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 r == nil { w, _ = ioutil.ReadAll(r.Body) _ = r.Body.Close() return false } // 正确情况的逻辑 } ``` 也就是说,尽量不要用 if-else 的方式处理错误,在 if 中处理错误即可。具体可以参考 effective go。 还有就是,重试最好也别写在错误处理里,万一你要重试 10 次咋办? |
12
azzwacb9001 2018-12-08 22:20:09 +08:00
....v2ex 不能使用 markdown 回复吗?
|
13
azzwacb9001 2018-12-08 22:20:52 +08:00
@Licsber 按理来说是这样,但上次我朋友跟我说 http.Get 在内部自带 goroutine 机制。我验证一下吧。
|
14
Licsber OP @azzwacb9001 谢谢! 我在试着用 RPC 重新写这一段代码 实在太丑了 而且 http 的超时我也没找到在哪....尴尬
|
15
Licsber OP @azzwacb9001 内部自带这个是指的服务端吧? 我觉得客户端没必要啊 并发打服务器玩吗?
|
16
azzwacb9001 2018-12-08 22:44:44 +08:00
@Licsber 是的我验证了一下,的确是顺序执行的 = =
|
17
goofool 2018-12-11 10:22:36 +08:00
server 端的 request 不需要自己 close
|