欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go?net?http超時應(yīng)用場景全面詳解

 更新時間:2024年01月04日 11:27:57   作者:Go語言教程  
HTTP是一個復(fù)雜的多階段協(xié)議,因此沒有一個一刀切的超時解決方案,在這篇文章中,我將分解您可能需要應(yīng)用超時的各個階段,并研究在服務(wù)器端和客戶端上執(zhí)行超時的不同方法

一、前言

在Go中編寫HTTP服務(wù)器或客戶端時,超時是最容易出錯、最微妙的事情之一:有很多選擇,錯誤在很長一段時間內(nèi)都不會產(chǎn)生任何后果,直到網(wǎng)絡(luò)出現(xiàn)故障,進(jìn)程掛起。

二、超時時間

2.1 SetDeadline

首先,您需要了解Go為實現(xiàn)超時而公開的網(wǎng)絡(luò)原語:Deadlines。

由net.Conn使用Set[Read|Write]Deadline(time.time)方法公開,Deadlines是一個絕對時間,當(dāng)達(dá)到該時間時,所有I/O操作都會失敗并出現(xiàn)超時錯誤。

Deadlines不是超時。一旦設(shè)置,它們將永遠(yuǎn)有效(或直到下一次調(diào)用SetDeadline),無論在此期間是否以及如何使用連接。因此,要使用SetDeadline構(gòu)建超時,您必須在每次讀/寫操作之前調(diào)用它。

您可能不想自己調(diào)用SetDeadline,而是讓net/http使用其更高級別的超時為您調(diào)用它。但是,請記住所有超時都是根據(jù)Deadlines實現(xiàn)的,因此它們不會在每次發(fā)送或接收數(shù)據(jù)時重置。

2.2 Server Timeouts

因此你想在互聯(lián)網(wǎng)上公開Go的帖子發(fā)現(xiàn)更多關(guān)于服務(wù)器超時的信息,特別是關(guān)于HTTP/2和Go 1.7錯誤的信息:

對于暴露在Internet上的HTTP服務(wù)器來說,強(qiáng)制客戶端連接超時是至關(guān)重要的。否則,速度非常慢或正在消失的客戶端可能會泄漏文件描述符,并最終導(dǎo)致以下情況:

http: Accept error: accept tcp [::]:80: accept4: 
too many open files; retrying in 5ms

在http.Server中公開了兩個超時:ReadTimeout和WriteTimeout。您可以通過顯式使用服務(wù)器來設(shè)置它們:

srv := &http.Server{
    ReadTimeout: 5 * time.Second,
    WriteTimeout: 10 * time.Second,
}
log.Println(srv.ListenAndServe())

ReadTimeout涵蓋了從接受連接到完全讀取請求正文的時間(如果您確實讀取了正文,否則到標(biāo)頭末尾)。它是通過在Accept之后立即調(diào)用SetReadDeadline在net/http中實現(xiàn)的。

WriteTimeout通常通過在readRequest結(jié)束時調(diào)用SetWriteDeadline來覆蓋從請求標(biāo)頭讀取結(jié)束到響應(yīng)寫入結(jié)束的時間(也稱為ServeHTTP的生存期)。

但是,當(dāng)連接是HTTPS時,在Accept之后會立即調(diào)用SetWriteDeadline,以便它也覆蓋作為TLS握手一部分寫入的數(shù)據(jù)包。令人煩惱的是,這意味著(僅在這種情況下)WriteTimeout最終包括頭讀取和第一個字節(jié)等待。

當(dāng)你處理不受信任的客戶端和/或網(wǎng)絡(luò)時,你應(yīng)該設(shè)置這兩個超時,這樣客戶端就不會因為寫或讀速度慢而中斷連接。

最后是http.TimeoutHandler。它不是Server參數(shù),而是一個限制ServeHTTP調(diào)用最長持續(xù)時間的Handler包裝器。它的工作方式是緩沖響應(yīng),如果超過最后期限,則發(fā)送504網(wǎng)關(guān)超時。請注意,它在1.6中被提出,在1.6.2中。

三、http.ListenAndServe 做的是錯誤的

順便說一句,這意味著繞過http.Server的包級便利功能,如http.ListenAndServe、http.Listen AndServeTLS和http.Serve,不適合公共Internet服務(wù)器。

這些函數(shù)將Tmeouts保留為默認(rèn)的off值,無法啟用它們,因此如果使用它們,很快就會出現(xiàn)連接泄漏和文件描述符用完的情況。我至少犯過六次這個錯誤。

相反,使用ReadTimeout和WriteTimeout創(chuàng)建一個http.Server實例,并使用其相應(yīng)的方法,就像上面幾段中的示例一樣。

3.1 streaming

非常令人惱火的是,沒有辦法從ServeHTTP訪問底層的net.Conn,因此打算流式傳輸響應(yīng)的服務(wù)器被迫取消設(shè)置WriteTimeout(這也可能是它們默認(rèn)為0的原因)。這是因為如果沒有net.Conne訪問,就無法在每次寫入之前調(diào)用SetWriteDeadline來實現(xiàn)適當(dāng)?shù)目臻e(而不是絕對)超時。

此外,無法取消被阻止的ResponseWriter.Write,因為沒有記錄ResponseWriter.Close(您可以通過接口升級訪問)來取消阻止并發(fā)寫入。因此,也沒有辦法用Timer手動構(gòu)建超時。

可悲的是,這意味著流媒體服務(wù)器無法真正保護(hù)自己免受慢速閱讀客戶端的攻擊。

3.2 Client Timeouts

客戶端超時可能更簡單,也可能更復(fù)雜,這取決于您使用的超時,但對于防止資源泄漏或陷入困境同樣重要。

最容易使用的是http.Client的Timeout字段。它涵蓋了整個交換,從Dial(如果不重用連接)到讀取主體。

c := &http.Client{
    Timeout: 15 * time.Second,
}
resp, err := c.Get("https://blog.filippo.io/")

與上面的服務(wù)器端案例一樣,包級別的函數(shù)(如http.Get請求客戶端在沒有超時的情況下使用,因此在開放式互聯(lián)網(wǎng)上使用是危險的。

為了進(jìn)行更精細(xì)的控制,您可以設(shè)置許多其他更具體的超時

  • net.Dialer.Timeout限制建立TCP連接所花費的時間(如果需要新的連接)。
  • http.Transport.TLS握手超時限制執(zhí)行TLS握手所花費的時間
  • http.Transport.ResponseHeaderTimeout限制讀取響應(yīng)標(biāo)頭所花費的時間。
  • http.Transport.ExpectContinueTimeout限制客戶端在發(fā)送包含Expect:100 continue的請求標(biāo)頭和接收發(fā)送正文的批準(zhǔn)之間等待的時間。
c := &http.Client{
    Transport: &http.Transport{
        Dial: (&net.Dialer{
                Timeout:   30 * time.Second,
                KeepAlive: 30 * time.Second,
        }).Dial,
        TLSHandshakeTimeout:   10 * time.Second,
        ResponseHeaderTimeout: 10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
    }
}

據(jù)我所知,沒有辦法具體限制發(fā)送請求所花費的時間。讀取請求正文所花費的時間可以通過time.Timer手動控制,因為它發(fā)生在Client方法返回之后(有關(guān)如何取消請求,請參閱下文)。

最后,1.7中新增了http.Transport.IdleConnTimeout。它不控制客戶端請求的阻塞階段,而是控制空閑連接在連接池中保持的時間。

請注意,客戶端默認(rèn)情況下會遵循重定向。http.Client.Timeout包括重定向后花費的所有時間,而細(xì)粒度超時是針對每個請求的,因為http.Transport是一個沒有重定向概念的較低級別系統(tǒng)。

3.3 Cancel and Context

nethttp提供了兩種取消客戶端請求的方法:request.cancel和1.7中新增的Context。

Request.Cancel是一個可選通道,當(dāng)設(shè)置并關(guān)閉時,會導(dǎo)致請求中止,就像達(dá)到Request.Timeout一樣。(它們實際上是通過相同的機(jī)制實現(xiàn)的,在寫這篇文章時,我在1.7中發(fā)現(xiàn)了一個錯誤,所有取消都會作為超時錯誤返回。)

我們可以使用Request.Cancel和time.Timer來構(gòu)建一個更精細(xì)的超時,允許流式傳輸,每次我們成功從Body讀取一些數(shù)據(jù)時都會將截止日期向后推:

package main
import (
  "io"
  "io/ioutil"
  "log"
  "net/http"
  "time"
)
func main() {
  c := make(chan struct{})
  timer := time.AfterFunc(5*time.Second, func() {
    close(c)
  })
        // Serve 256 bytes every second.
  req, err := http.NewRequest("GET", "http://httpbin.org/range/2048?duration=8&chunk_size=256", nil)
  if err != nil {
    log.Fatal(err)
  }
  req.Cancel = c
  log.Println("Sending request...")
  resp, err := http.DefaultClient.Do(req)
  if err != nil {
    log.Fatal(err)
  }
  defer resp.Body.Close()
  log.Println("Reading body...")
  for {
    timer.Reset(2 * time.Second)
                // Try instead: timer.Reset(50 * time.Millisecond)
    _, err = io.CopyN(ioutil.Discard, resp.Body, 256)
    if err == io.EOF {
      break
    } else if err != nil {
      log.Fatal(err)
    }
  }
}

在上面的例子中,我們在請求的Do階段設(shè)置了5秒的超時,但隨后讀取正文,每次超時2秒??梢杂肋h(yuǎn)這樣流媒體,而不會有陷入困境的風(fēng)險。如果在超過2秒的時間內(nèi)沒有收到正文數(shù)據(jù),那么io.CopyN將返回net/http:requestcancelled。

在1.7中,上下文包升級為標(biāo)準(zhǔn)庫。關(guān)于上下文有很多需要學(xué)習(xí)的地方,但就目的而言,您應(yīng)該知道它們會取代和棄用Request.Cancel。

要使用Contexts取消請求,我們只需獲取一個新的Context及其帶有Context.WithCancel的cancel()函數(shù),并使用request.WithContext創(chuàng)建一個綁定到它的request。當(dāng)我們想取消請求時,我們通過調(diào)用cancel來取消Context:

ctx, cancel := context.WithCancel(context.TODO())
timer := time.AfterFunc(5*time.Second, func() {
  cancel()
})
req, err := http.NewRequest("GET", "http://httpbin.org/range/2048?duration=8&chunk_size=256", nil)
if err != nil {
  log.Fatal(err)
}
req = req.WithContext(ctx)

以上就是Go net http超時應(yīng)用場景全面詳解的詳細(xì)內(nèi)容,更多關(guān)于Go net http超時的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go語言實現(xiàn)通過FTP庫自動上傳web日志

    go語言實現(xiàn)通過FTP庫自動上傳web日志

    這篇文章主要介紹了go語言實現(xiàn)通過FTP庫自動上傳web日志,非常簡單實用,需要的小伙伴快來參考下吧。
    2015-03-03
  • Golang標(biāo)準(zhǔn)庫time包日常用法小結(jié)

    Golang標(biāo)準(zhǔn)庫time包日常用法小結(jié)

    本文主要介紹了Golang標(biāo)準(zhǔn)庫time包日常用法小結(jié),可以通過它們來獲取當(dāng)前時間、創(chuàng)建指定時間、解析時間字符串、控制時間間隔等操作,感興趣的可以了解一下
    2023-11-11
  • go語言計算兩個時間的時間差方法

    go語言計算兩個時間的時間差方法

    這篇文章主要介紹了go語言計算兩個時間的時間差方法,涉及Python操作時間的技巧,需要的朋友可以參考下
    2015-03-03
  • Golang中反射的常見用法分享

    Golang中反射的常見用法分享

    本篇文章主要為大家詳細(xì)介紹一些Go語言中常見的反射用法,涵蓋了常見的數(shù)據(jù)類型的反射操作。文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2023-01-01
  • Go日志框架zap增強(qiáng)及源碼解讀

    Go日志框架zap增強(qiáng)及源碼解讀

    這篇文章主要為大家介紹了Go日志框架zap增強(qiáng)及源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Go數(shù)組的具體使用

    Go數(shù)組的具體使用

    Go語言中的數(shù)組是一種固定長度的數(shù)據(jù)結(jié)構(gòu),它包含一組按順序排列的元素,每個元素都具有相同的類型,本文主要介紹了Go數(shù)組的具體使用,包括聲明數(shù)組、初始化數(shù)組、訪問數(shù)組元素等,感興趣的可以了解下
    2023-11-11
  • 如何解析golang中Context在HTTP服務(wù)中的角色

    如何解析golang中Context在HTTP服務(wù)中的角色

    這篇文章主要介紹了如何解析golang中Context在HTTP服務(wù)中的角色問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 基于Go語言實現(xiàn)應(yīng)用IP防火墻

    基于Go語言實現(xiàn)應(yīng)用IP防火墻

    在公司里面經(jīng)常會聽到某應(yīng)用有安全漏洞問題,沒有做安全加固,IP防火墻就是一個典型的安全加固解決方案,下面我們就來學(xué)習(xí)一下如何使用go語言實現(xiàn)IP防火墻吧
    2023-11-11
  • Go設(shè)計模式之備忘錄模式講解和代碼示例

    Go設(shè)計模式之備忘錄模式講解和代碼示例

    備忘錄是一種行為設(shè)計模式, 允許生成對象狀態(tài)的快照并在以后將其還原,本文就通過代碼示例給大家講講Go備忘錄模式,感興趣的小伙伴跟著小編一起來看看吧
    2023-08-08
  • 從零封裝Gin框架配置初始化全局變量

    從零封裝Gin框架配置初始化全局變量

    這篇文章主要為大家介紹了從零封裝Gin框架配置初始化全局變量,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01

最新評論