Go 語言 HTTP 要求逾時入門

來源:互聯網
上載者:User
在分布式系統中,逾時是基本可靠性概念之一。就像這條 [tweet](https://twitter.com/copyconstruct/status/1025241837034860544) 中提到的,它可以緩和分布式系統中不可避免出現的失敗所帶來的影響。## 問題> 如何條件性地類比 504 http.StatusGatewayTimeout 響應。當嘗試在 [zalando/skipper](https://github.com/zalando/skipper/issues/633) 中實現 OAuth token 驗證時,我不得不理解並嘗試使用 httptest 實現一個測試用來在服務端逾時的時候 [類比一個](https://stackoverflow.com/questions/51319726/how-to-mimic-504-timeout-error-for-http-request-inside-a-test-in-go) [504 http.StatusGatewayTimeout](https://stackoverflow.com/questions/51319726/how-to-mimic-504-timeout-error-for-http-request-inside-a-test-in-go)。但因為服務端的延遲,只產生了用戶端的逾時。作為這門語言的初學者,跟大多數人一樣,我像下面這樣建立了一個標準的帶有逾時的 HTTP Client。```goclient := http.Client{Timeout: 5 * time.Second}```當想要建立一個 client 用以發送 http 請求的時候,上面的代碼看起來非常簡單和直觀。但是它下面卻隱藏了大量低層次的細節,包括用戶端逾時,服務端逾時和負載平衡逾時。## 用戶端逾時用戶端的 http 請求逾時有多種形式,具體取決於在整個請求流程中逾時幀的位置。整個請求響應流程由 `Dialer`,`TLS Handshake`,`Request Header`,`Request Body`,`Response Header` 和 `Response Body` 構成。根據請求響應流程中上述不同的組件,Go 提供了如下方式來建立帶有逾時的請求。* `http.client`* `context`* `http.Transport`## http.client:`http.client` 逾時是逾時的高層實現,包含了從 `Dial` 到 `Response Body` 的整個請求流程。`http.client` 的實現提供了一個結構體類型可以接受一個額外的 `time.Duration` 類型的 `Timeout` 屬性。這個參數定義了從請求開始到響應訊息體被完全接收的時間限制。```goclient := http.Client{Timeout: 5 * time.Second}```## contextGo 語言的 `context` 包提供了一些有用的工具通過使用 `WithTimeout`,`WithDeadline` 和 `WithCancel` 方法來處理逾時,Deadline 和可取消的請求。有了 `WithTimeout`,你就可以通過 `req.WithContext` 方法給 `http.Request` 添加一個逾時時間了。```goctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)defer cancel()req, err := http.NewRequest("GET", url, nil)if err != nil { t.Error("Request error", err)}resp, err := http.DefaultClient.Do(req.WithContext(ctx))```## http.Transport:你也可以通過使用帶有 `DialContext` 的自訂 `http.Transport` 來建立 `http.client` 這種低層次的實現來指定逾時時間。```gotransport := &http.Transport{ DialContext: (&net.Dialer{ Timeout: timeout, }).DialContext,}client := http.Client{Transport: transport}```## 解決方案根據上述的問題和各類選擇,我通過 `context.WithTimeout()` 建立了一個 `http.request`。但仍然失敗並得到了以下錯誤。```client_test.go:40: Response error Get http://127.0.0.1:49597: context deadline exceeded```## 服務端逾時使用 `context.WithTimeout()` 的問題是它仍然只是類比的請求的用戶端。萬一請求的頭部或者訊息體超出了預定義的逾時時間,請求會在用戶端直接失敗而不會從服務端返回 `504 http.StatusGatewayTimeout` 狀態代碼。建立一個每次都逾時的 httptest 服務代碼如下:```gohttptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request){ w.WriteHeader(http.StatusGatewayTimeout)}))```但我只希望服務端根據用戶端設定的值逾時。為了讓服務端根據用戶端逾時時間返回 504 狀態代碼,你可以使用 `http.TimeoutHandler()` 函數來封裝 handler 使請求在服務端失敗。如下為符合情境需求的可啟動並執行測試代碼。```gofunc TestClientTimeout(t *testing.T) { handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { d := map[string]interface{}{ "id": "12", "scope": "test-scope", } time.Sleep(100 * time.Millisecond) //<- Any value > 20ms b, err:= json.Marshal(d) if err != nil { t.Error(err) } io.WriteString(w, string(b)) w.WriteHeader(http.StatusOK) }) backend := httptest.NewServer(http.TimeoutHandler(handlerFunc, 20*time.Millisecond, "server timeout")) url := backend.URL req, err := http.NewRequest("GET", url, nil) if err != nil { t.Error("Request error", err) return } resp, err := http.DefaultClient.Do(req) if err != nil { t.Error("Response error", err) return } defer resp.Body.Close()}```在項目 [zalando/skipper](https://github.com/zalando/skipper/) 的 [oauth_test/TestOAuth2TokenTimeout](https://github.com/zalando/skipper/blob/master/filters/auth/oauth_test.go#L378:6) 的實現中包含了上述問題的具體資訊。也許 Go 語言初學者對於理解 http 逾時高層次的原理是比較有用的。但如果你想知道更多關於 Go 中 `http timeouts` 的細節,這篇 [Cloudflare](https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/) 上的文章值得一讀。

via: https://medium.com/@addityasingh/http-request-timeouts-in-go-for-beginners-fe6445137c90

作者:Aditya pratap singh 譯者:alfred-zhong 校對:polaris1119

本文由 GCTT 原創編譯,Go語言中文網 榮譽推出

本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽

185 次點擊  
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.