首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
beego
拉钩
V2EX  ›  Go

Go 的 http.Get 是阻塞的吗?还是说有超时呢?求问

  •  1
     
  •   Licsber · 8 天前 · 1286 次点击
    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 写东西 客户端也能收到
    客户端调用这个之后 貌似什么都不会发生?

    20 回复  |  直到 2018-12-12 22:21:25 +08:00
        1
    Licsber   8 天前
    为啥我的代码会写的这么丑呢..
    求解答
        2
    yufpga   8 天前 via Android
    是同步阻塞的,r.Body 必须显式的 close 掉,不然,不断有请求,但资源没释放,程序很快会崩掉的。你上面那段代码问题很多,首先要检察 err,而不是去判断 r 是否是 nil。还有没有关闭 r.Body
        3
    yufpga   8 天前 via Android
    哦,看错了,有 close,还是看 golang 标准库中的例子吧,挺别扭的
        4
    mengyaoss77   8 天前 via Android
    好好利用 error 啊,少用 else 多用提前 return.
        5
    Licsber   8 天前
    @yufpga 也就是说 http.Get 这个方法不会异步执行是吗
    检查了 err 是 connect time out .. 这个超时是哪里规定的呢
    他不会一直等待我的服务端 r.Body.Close()吗
    我在想这个要不要改成 RPC 会不会好一点呢
        6
    Licsber   8 天前
    @mengyaoss77 我觉得最好玩的就是 如果没有响应(r == nil)的话
    我再延时 5s 居然就能读取了
    所以我就有一种 Get 是异步执行的错觉
    而且服务端的那段代码理论上不会执行很久
    就很奇怪
        7
    yufpga   8 天前 via Android
    http.Get 对于调用者来说自然是同步阻塞的,对于失败的请求,你自然不需要去调用 r.Body.Close,标准库已经帮你做了,timeout 是因为标准库内部使用了 context,控制了某一次请求的生命周期,http.Get 其实是使用了 DefaultClient, 如果需要自己设置这个超时时间,你需要设置 client 的 Timeout 属性。多看源码吧。
        8
    Licsber   8 天前
    @yufpga 好的 谢谢!🙏
        9
    azzwacb9001   8 天前
    @yufpga 您好,我想请问一下,如果我在一个 for 循环中调用 http.Get (不使用 goroutine ),这些 http 请求是会逐个执行,还是并发执行呢?
        10
    Licsber   8 天前
    @azzwacb9001 我觉得当然是逐个执行呀 想想 for 循环里随便一个表达式 只要不加 go 都是执行完上一条才下一条
        11
    azzwacb9001   8 天前
    无法回答楼主的问题,但是顺道提一下,最好不要这么写

    ```
    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   8 天前
    ....v2ex 不能使用 markdown 回复吗?
        13
    azzwacb9001   8 天前
    @Licsber 按理来说是这样,但上次我朋友跟我说 http.Get 在内部自带 goroutine 机制。我验证一下吧。
        14
    Licsber   8 天前
    @azzwacb9001 谢谢! 我在试着用 RPC 重新写这一段代码 实在太丑了 而且 http 的超时我也没找到在哪....尴尬
        15
    Licsber   8 天前
    @azzwacb9001 内部自带这个是指的服务端吧? 我觉得客户端没必要啊 并发打服务器玩吗?
        16
    azzwacb9001   8 天前
    @Licsber 是的我验证了一下,的确是顺序执行的 = =
        17
    goofool   5 天前
    server 端的 request 不需要自己 close
        18
    Licsber   4 天前
    @goofool 是这样, 如果我想关闭这个链接该怎么办呢. 比如用户填写表单错误的时候要让代码不要向下执行, 谢谢.
        19
    goofool   4 天前 via Android
    @Licsber 额,return 就可以了
        20
    Licsber   4 天前
    @goofool 啊哈 .
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1240 人在线   最高记录 4019   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.1 · 19ms · UTC 17:12 · PVG 01:12 · LAX 09:12 · JFK 12:12
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1