Go設(shè)置http請求超時(shí)的方法實(shí)現(xiàn)
背景
最近接手了一個(gè)老項(xiàng)目進(jìn)行維護(hù),發(fā)現(xiàn)其中有個(gè)關(guān)于 http 請求的方法設(shè)置的 timeout 沒有生效,很奇怪!
一開始查看代碼并沒有發(fā)現(xiàn)什么可疑點(diǎn),后查看了源碼,打斷點(diǎn)調(diào)試才發(fā)現(xiàn)問題所在,這里簡單記錄復(fù)盤一下。
說明:本篇的源碼的 go 版本是 1.20.2 。
問題
示例代碼
package main
import (
"context"
"fmt"
"net/http"
"time"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://www.baidu.com", nil)
if err != nil {
panic(err)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
defer cancel()
req.WithContext(ctx)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
//resp.Write(os.Stdout)
fmt.Println("end: ", resp.StatusCode)
}
程序正常跑完并輸出了,但是預(yù)期的是 http.DefaultClient.Do(req) 這里會直接報(bào)錯(cuò),難道請求 1ms 就結(jié)束了??Why???
大家可以自己看下這段代碼哪里有問題。
先說解決,其實(shí)就是 req.WithContext(ctx) 生成的是一個(gè)新的 http.Request 對象,上述的問題代碼中并沒有將其賦值給當(dāng)前的 http.Request。大意了,沒有閃。
req = req.WithContext(ctx)
WithContext 方法的源碼如下(net/http/request.go 356)
func (r *Request) WithContext(ctx context.Context) *Request {
if ctx == nil {
panic("nil context")
}
r2 := new(Request)
*r2 = *r
r2.ctx = ctx
return r2
}
請求超時(shí)設(shè)置
翻了下源碼,看了下超時(shí)設(shè)置的方式,http 設(shè)置超時(shí)主要有兩種方式:
- http.Client
c := http.Client{
Timeout: time.Minute,
}
c.Do(req)
- http.Request 設(shè)置 context 超時(shí)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() req = req.WithContext(ctx)
在 Client 上指定 Timeout 會作用于通過該 Client 發(fā)起的所有請求,而 Request 設(shè)置 Context,僅針對這一次請求。使用的時(shí)候需要注意自己的場景。
設(shè)置 Tcp 連接階段的超時(shí)可以這樣:
client := http.Client{
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: 2 * time.Second, // tcp 連接時(shí)設(shè)置的連接超時(shí)
Deadline: time.Now().Add(3 * time.Second), // 超時(shí)強(qiáng)制關(guān)閉
}).Dial,
TLSHandshakeTimeout: 2 * time.Second, //https 握手超時(shí)
},
Timeout: 5 * time.Second,
}
可以設(shè)置 Transport 中的 Dial。
總結(jié)
平常自己使用 http 發(fā)送請求設(shè)置超時(shí),都是直接給 http.Client 對象設(shè)置 Timeout 屬性,很少使用這種對單個(gè) Request 設(shè)置超時(shí)的。
其實(shí)還是個(gè)熟練度問題,平常源碼讀的比較少。有空讀讀源碼不僅可以在使用代碼的時(shí)候更得心應(yīng)手,也能夠?qū)W習(xí)借鑒源碼的代碼設(shè)計(jì)實(shí)現(xiàn)。對自己平常經(jīng)常需要使用的庫,還是建議都過一遍源碼,很不錯(cuò)的一個(gè)打發(fā)空閑時(shí)間的方式。
以上就是Go設(shè)置http請求超時(shí)的方法實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Go設(shè)置http請求超時(shí)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解Golang如何優(yōu)雅的終止一個(gè)服務(wù)
后端服務(wù)通常會需要?jiǎng)?chuàng)建子協(xié)程來進(jìn)行相應(yīng)的作業(yè),但進(jìn)程接受到終止信號或正常結(jié)束時(shí),并沒有判斷或等待子協(xié)程執(zhí)行結(jié)束,下面這篇文章主要給大家介紹了關(guān)于Golang如何優(yōu)雅的終止一個(gè)服務(wù)的相關(guān)資料,需要的朋友可以參考下2022-03-03
使用Gin框架返回JSON、XML和HTML數(shù)據(jù)
Gin是一個(gè)高性能的Go語言Web框架,它不僅提供了簡潔的API,還支持快速的路由和中間件處理,在Web開發(fā)中,返回JSON、XML和HTML數(shù)據(jù)是非常常見的需求,本文將介紹如何使用Gin框架來返回這三種類型的數(shù)據(jù),需要的朋友可以參考下2024-08-08
Golang實(shí)現(xiàn)web文件共享服務(wù)的示例代碼
這篇文章主要介紹了Golang實(shí)現(xiàn)web文件共享服務(wù)的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-10-10
Golang服務(wù)中context超時(shí)處理的方法詳解
在Go語言中,Context是一個(gè)非常重要的概念,它存在于一個(gè)完整的業(yè)務(wù)生命周期內(nèi),Context類型是一個(gè)接口類型,在實(shí)際應(yīng)用中,我們可以使用Context包來傳遞請求的元數(shù)據(jù),本文將給大家介紹Golang服務(wù)中context超時(shí)處理的方法和超時(shí)原因,需要的朋友可以參考下2023-05-05

