Go 的 http.Get 是阻塞的吗?还是说有超时呢?求问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Licsber
0.04D
V2EX    Go 编程语言

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

  •  1
     
  •   Licsber
    licsber 2018-12-08 19:26:32 +08:00 4989 次点击
    这是一个创建于 2548 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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
    Licsber
        1
    Licsber  
    OP
       2018-12-08 19:45:08 +08:00
    为啥我的代码会写的这么丑呢..
    求解答
    yufpga
        2
    yufpga  
       2018-12-08 19:59:16 +08:00 via Android
    是同步阻塞的,r.Body 必须显式的 close 掉,不然,不断有请求,但资源没释放,程序很快会崩掉的。你上面那段代码问题很多,首先要检察 err,而不是去判断 r 是否是 nil。还有没有关闭 r.Body
    yufpga
        3
    yufpga  
       2018-12-08 20:01:41 +08:00 via Android
    哦,看错了,有 close,还是看 golang 标准库中的例子吧,挺别扭的
    mengyaoss77
        4
    mengyaoss77  
       2018-12-08 20:05:19 +08:00 via Android
    好好利用 error 啊,少用 else 多用提前 return.
    Licsber
        5
    Licsber  
    OP
       2018-12-08 20:05:34 +08:00
    @yufpga 也就是说 http.Get 这个方法不会异步执行是吗
    检查了 err 是 connect time out .. 这个超时是哪里规定的呢
    他不会一直等待我的服务端 r.Body.Close()吗
    我在想这个要不要改成 RPC 会不会好一点呢
    Licsber
        6
    Licsber  
    OP
       2018-12-08 20:07:32 +08:00
    @mengyaoss77 我觉得最好玩的就是 如果没有响应(r == nil)的话
    我再延时 5s 居然就能读取了
    所以我就有一种 Get 是异步执行的错觉
    而且服务端的那段代码理论上不会执行很久
    就很奇怪
    yufpga
        7
    yufpga  
       2018-12-08 20:26:30 +08:00 via Android
    http.Get 对于调用者来说自然是同步阻塞的,对于失败的请求,你自然不需要去调用 r.Body.Close,标准库已经帮你做了,timeout 是因为标准库内部使用了 context,控制了某一次请求的生命周期,http.Get 其实是使用了 DefaultClient, 如果需要自己设置这个超时时间,你需要设置 client 的 Timeout 属性。多看源码吧。
    Licsber
        8
    Licsber  
    OP
       2018-12-08 20:40:31 +08:00
    @yufpga 好的 谢谢!
    azzwacb9001
        9
    azzwacb9001  
       2018-12-08 22:12:26 +08:00
    @yufpga 您好,我想请问一下,如果我在一个 for 循环中调用 http.Get (不使用 goroutine ),这些 http 请求是会逐个执行,还是并发执行呢?
    Licsber
    &bsp;   10
    Licsber  
    OP
       2018-12-08 22:19:18 +08:00
    @azzwacb9001 我觉得当然是逐个执行呀 想想 for 循环里随便一个表达式 只要不加 go 都是执行完上一条才下一条
    azzwacb9001
        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 次咋办?
    azzwacb9001
        12
    azzwacb9001  
       2018-12-08 22:20:09 +08:00
    ....v2ex 不能使用 markdown 回复吗?
    azzwacb9001
        13
    azzwacb9001  
       2018-12-08 22:20:52 +08:00
    @Licsber 按理来说是这样,但上次我朋友跟我说 http.Get 在内部自带 goroutine 机制。我验证一下吧。
    Licsber
        14
    Licsber  
    OP
       2018-12-08 22:32:46 +08:00
    @azzwacb9001 谢谢! 我在试着用 RPC 重新写这一段代码 实在太丑了 而且 http 的超时我也没找到在哪....尴尬
    Licsber
        15
    Licsber  
    OP
       2018-12-08 22:33:16 +08:00
    @azzwacb9001 内部自带这个是指的服务端吧? 我觉得客户端没必要啊 并发打服务器玩吗?
    azzwacb9001
        16
    azzwacb9001  
       2018-12-08 22:44:44 +08:00
    @Licsber 是的我验证了一下,的确是顺序执行的 = =
    goofool
        17
    goofool  
       2018-12-11 10:22:36 +08:00
    server 端的 request 不需要自己 close
    Licsber
        18
    Licsber  
    OP
       2018-12-12 15:31:24 +08:00
    @goofool 是这样, 如果我想关闭这个链接该怎么办呢. 比如用户填写表单错误的时候要让代码不要向下执行, 谢谢.
    goofool
        19
    goofool  
       2018-12-12 15:55:56 +08:00 via Android
    @Licsber 额,return 就可以了
    Licsber
        20
    Licsber  
    OP
       2018-12-12 22:21:25 +08:00
    @goofool 啊哈 .
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     815 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 22:18 PVG 06:18 LAX 14:18 JFK 17:18
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86