Go語言http.Get()逾時設定(更新)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

上次寫了一遍日誌分享http.Get()設定逾時的方案(上篇文章),後來自己過了一遍代碼發現邏輯上有問題。

在Dail之後設定了Deadline,之後就沒再重新設定。這對於不重用串連的http請求是沒有問題的,但是Go的http庫是支援keep-alive的,可以重用TCP/IP串連。這意味著一個串連過了逾時時間後再被使用,就會出現逾時錯誤,因為沒有再重設逾時時間。

拿上次的實驗代碼,在發送請求時加一個keep-alive頭,然後每次發送請求前加個Sleep,就可以重新以上情況。

怎樣做到每次使用一個串連發送和接收前就設定逾時呢?我想了個辦法是在Dial回調返回自己封裝過的TimeoutConn,間接的調用真實的Conn,這樣就可以再每次Read和Write之前設定逾時時間了。

以下是修改後的實驗代碼:

//// How to set timeout for http.Get() in golang//package mainimport (    "io"    "io/ioutil"    "log"    "net"    "net/http"    "sync"    "time")type TimeoutConn struct {    conn    net.Conn    timeout time.Duration}func NewTimeoutConn(conn net.Conn, timeout time.Duration) *TimeoutConn {    return &TimeoutConn{        conn:    conn,        timeout: timeout,    }}func (c *TimeoutConn) Read(b []byte) (n int, err error) {    c.SetReadDeadline(time.Now().Add(c.timeout))    return c.conn.Read(b)}func (c *TimeoutConn) Write(b []byte) (n int, err error) {    c.SetWriteDeadline(time.Now().Add(c.timeout))    return c.conn.Write(b)}func (c *TimeoutConn) Close() error {    return c.conn.Close()}func (c *TimeoutConn) LocalAddr() net.Addr {    return c.conn.LocalAddr()}func (c *TimeoutConn) RemoteAddr() net.Addr {    return c.conn.RemoteAddr()}func (c *TimeoutConn) SetDeadline(t time.Time) error {    return c.conn.SetDeadline(t)}func (c *TimeoutConn) SetReadDeadline(t time.Time) error {    return c.conn.SetReadDeadline(t)}func (c *TimeoutConn) SetWriteDeadline(t time.Time) error {    return c.conn.SetWriteDeadline(t)}func main() {    client := &http.Client{        Transport: &http.Transport{            Dial: func(netw, addr string) (net.Conn, error) {                log.Printf("dial to %s://%s", netw, addr)                conn, err := net.DialTimeout(netw, addr, time.Second*2)                if err != nil {                    return nil, err                }                return NewTimeoutConn(conn, time.Second*2), nil            },            ResponseHeaderTimeout: time.Second * 2,        },    }    addr := StartTestServer()    SendTestRequest(client, "1st", addr, "normal")    SendTestRequest(client, "2st", addr, "normal")    SendTestRequest(client, "3st", addr, "timeout")    SendTestRequest(client, "4st", addr, "normal")    time.Sleep(time.Second * 3)    SendTestRequest(client, "5st", addr, "normal")}func StartTestServer() string {    listener, err := net.Listen("tcp", ":0")    if err != nil {        log.Fatalf("failed to listen - %s", err.Error())    }    wg := new(sync.WaitGroup)    wg.Add(1)    go func() {        http.HandleFunc("/normal", func(w http.ResponseWriter, req *http.Request) {            time.Sleep(1000 * time.Millisecond)            io.WriteString(w, "ok")        })        http.HandleFunc("/timeout", func(w http.ResponseWriter, req *http.Request) {            time.Sleep(2500 * time.Millisecond)            io.WriteString(w, "ok")        })        wg.Done()        err = http.Serve(listener, nil)        if err != nil {            log.Fatalf("failed to start HTTP server - %s", err.Error())        }    }()    wg.Wait()    log.Printf("start http server at http://%s/", listener.Addr())    return listener.Addr().String()}func SendTestRequest(client *http.Client, id, addr, path string) {    req, err := http.NewRequest("GET", "http://"+addr+"/"+path, nil)    if err != nil {        log.Fatalf("new request failed - %s", err)    }    req.Header.Add("Connection", "keep-alive")    switch path {    case "normal":        if resp, err := client.Do(req); err != nil {            log.Fatalf("%s request failed - %s", id, err)        } else {            result, err2 := ioutil.ReadAll(resp.Body)            if err2 != nil {                log.Fatalf("%s response read failed - %s", id, err2)            }            resp.Body.Close()            log.Printf("%s request - %s", id, result)        }    case "timeout":        if _, err := client.Do(req); err == nil {            log.Fatalf("%s request not timeout", id)        } else {            log.Printf("%s request - %s", id, err)        }    }}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.