गोलंग में http.Get () अनुरोधों के लिए टाइमआउट कैसे सेट करें?


106

मैं गो में एक URL लाने वाला हूं और लाने के लिए URL की एक सूची है। मैं http.Get()प्रत्येक URL को अनुरोध भेजता हूं और उनकी प्रतिक्रिया प्राप्त करता हूं ।

resp,fetch_err := http.Get(url)

मैं प्रत्येक अनुरोध के लिए कस्टम टाइमआउट कैसे सेट कर सकता हूं? (डिफ़ॉल्ट समय बहुत लंबा है और इससे मेरा भ्रूण वास्तव में धीमा हो जाता है।) मैं चाहता हूं कि मेरा भ्रूण लगभग 40-45 सेकंड का समय समाप्त हो जाए, जिसके बाद उसे "अनुरोध समय समाप्त" करके अगले URL पर जाना चाहिए।

इसे कैसे प्राप्त किया जा सकता है?


1
बस दे तुम लोगों को पता है कि मैं इस तरह से और अधिक सुविधाजनक पाया (डायल टाइमआउट अच्छी तरह से काम नहीं करता है अगर वहाँ कम से कम मेरे लिए नेटवर्क मुद्दे हैं,): blog.golang.org/context
Audrius

@Audrius किसी भी विचार क्यों डायल टाइमआउट काम नहीं करता है जब नेटवर्क मुद्दे हैं? मुझे लगता है कि मैं वही देख रहा हूं। मैंने सोचा कि डायलटाइमआउट किस लिए था?!?
जॉर्डन

@ जोर्डन हार्ड बताने के लिए जैसा कि मैंने लाइब्रेरी कोड में गहरा नहीं किया है। मैंने अपना समाधान नीचे पोस्ट किया है। मैं इसे उत्पादन में काफी समय से उपयोग कर रहा हूं और अब तक यह "सिर्फ काम करता है" (tm)।
ऑड्रियस

जवाबों:


255

जाहिर तौर पर गो 1.3 http.Client में टाइमआउट फील्ड है

client := http.Client{
    Timeout: 5 * time.Second,
}
client.Get(url)

मेरे लिए यही चाल चली गई।


10
खैर, यह मेरे लिए काफी अच्छा है। खुशी है कि मैंने थोड़ा नीचे स्क्रॉल किया :)
जेम्स एडम

5
क्या अनुरोध के अनुसार अलग टाइमआउट करने का कोई तरीका है?
अरनौद रिनक्विन

11
जब टाइमआउट हिट होता है तो क्या होता है? क्या Getकोई त्रुटि लौटाता है? मैं थोड़ा भ्रमित हूं क्योंकि गोडॉक Clientकहता है: टाइमर गेट, हेड, पोस्ट या डू रिटर्न के बाद चलता रहता है और रिस्पॉन्स के पढ़ने में बाधा डालता है । बॉडी तो क्या इसका मतलब यह है कि या तो पढ़ना Get या पढ़ना Response.Bodyएक त्रुटि से बाधित हो सकता है?
एवि फ्लैक्स

1
प्रश्न, http.Client.Timeoutबनाम क्या अंतर है http.Transport.ResponseHeaderTimeout?
रॉय ली

2
@ रोली डॉक्स के अनुसार मुख्य अंतरों में से एक: http.Client.Timeoutप्रतिक्रिया शरीर को पढ़ने का समय शामिल है, http.Transport.ResponseHeaderTimeoutइसमें शामिल नहीं है।
imwill

53

आपको अपने स्वयं के ग्राहक को अपने स्वयं के परिवहन के साथ सेट करने की आवश्यकता है जो एक कस्टम डायल फ़ंक्शन का उपयोग करता है जो डायलटाइमआउट के आसपास लपेटता है

जैसे (पूरी तरह से कुछ अपरीक्षित ) इस :

var timeout = time.Duration(2 * time.Second)

func dialTimeout(network, addr string) (net.Conn, error) {
    return net.DialTimeout(network, addr, timeout)
}

func main() {
    transport := http.Transport{
        Dial: dialTimeout,
    }

    client := http.Client{
        Transport: &transport,
    }

    resp, err := client.Get("http://some.url")
}

आपका बहुत बहुत धन्यवाद! यह ठीक वही चीज है जिसकी मुझे तलाश थी।
pymd

net.ialTimeout का ट्रांसपोर्ट पर उपयोग करने से क्या फायदा है। Zzzz के उत्तर के द्वारा बताया गया।
डेनियल बी

4
@ डैनियल बी: आप गलत सवाल पूछ रहे हैं। यह फायदे के बारे में नहीं है, लेकिन प्रत्येक कोड क्या करता है। डायलटाइमआउट कूदता है यदि सर्वर को डिस्टर्ब नहीं किया जा सकता है जबकि अन्य टाइमआउट किक करते हैं यदि स्थापित कनेक्शन पर कुछ संचालन में बहुत लंबा समय लगता है। यदि आपके टारगेट सर्वर जल्दी से कनेक्शन स्थापित करते हैं, लेकिन तब धीमे-धीमे शुरू हो जाते हैं तो डायल टाइमआउट मदद नहीं करेगा।
वोल्कर

1
@ वोलर, आपके उत्तर के लिए धन्यवाद। वास्तव में मुझे इसका एहसास हुआ: यह ट्रांसपोर्ट जैसा लगता है। ResponseHeaderTimeout रीड टाइमआउट सेट करता है, यह कनेक्शन स्थापित होने के बाद का समय है, जबकि आपका डायल टाइमआउट है। Dmichael द्वारा समाधान डायल टाइमआउट और रीड टाइमआउट दोनों से संबंधित है।
डेनियल बी

1
@ जोनो: गो में कोई कास्ट नहीं हैं। ये प्रकार रूपांतरण हैं।
वोल्कर

31

वोल्कर के उत्तर में जोड़ने के लिए, यदि आप कनेक्ट टाइमआउट के अलावा रीड / राइट टाइमआउट सेट करना चाहते हैं, तो आप निम्न की तरह कुछ कर सकते हैं

package httpclient

import (
    "net"
    "net/http"
    "time"
)

func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) {
    return func(netw, addr string) (net.Conn, error) {
        conn, err := net.DialTimeout(netw, addr, cTimeout)
        if err != nil {
            return nil, err
        }
        conn.SetDeadline(time.Now().Add(rwTimeout))
        return conn, nil
    }
}

func NewTimeoutClient(connectTimeout time.Duration, readWriteTimeout time.Duration) *http.Client {

    return &http.Client{
        Transport: &http.Transport{
            Dial: TimeoutDialer(connectTimeout, readWriteTimeout),
        },
    }
}

इस कोड का परीक्षण किया गया है और उत्पादन में काम कर रहा है। परीक्षणों के साथ पूर्ण जिस्म यहाँ उपलब्ध है https://gist.github.com/dmichael/5710968

इस बात से अवगत रहें कि आपको प्रत्येक अनुरोध के लिए एक नया ग्राहक बनाने की आवश्यकता होगी क्योंकि conn.SetDeadlineइससे भविष्य में एक बिंदु का संदर्भ मिलता हैtime.Now()


क्या आपको con.SetDeadline के रिटर्न मान की जाँच नहीं करनी चाहिए?
एरिक अर्बन

3
यह समय-सीमा मुख्य कनेक्शनों के साथ काम नहीं करती है, जो कि डिफ़ॉल्ट है और अधिकांश लोगों को मेरी कल्पना का उपयोग करना चाहिए। यहाँ मैं इससे निपटने के लिए क्या कर रहा हूँ: gist.github.com/seantalts/11266762
xitrium

अतिरिक्त इनपुट के लिए @xitrium और एरिक को धन्यवाद।
दशमी

मुझे ऐसा महसूस हो रहा है कि जैसा आपने कहा है कि हमें प्रत्येक अनुरोध के लिए एक नया ग्राहक बनाने की आवश्यकता नहीं है। चूंकि डायल एक फ़ंक्शन है जो मुझे लगता है कि यह हर बार कॉल करने पर आपको उसी क्लाइंट में प्रत्येक अनुरोध भेजता है।
ए-लेटबी

आप सुनिश्चित करें कि आपको हर बार एक नए ग्राहक की आवश्यकता है? हर बार यह डायल करने के बजाय, net.Dial का उपयोग करने के बजाय, यह फ़ंक्शन का उपयोग करेगा जो TimeoutDialer बनाता है। यह एक नया कनेक्शन है, समय सीमा का मूल्यांकन हर बार, एक नए समय से किया जाता है। अब () कॉल करें।
कलकवेल

16

यदि आप इसे अनुरोध के अनुसार करना चाहते हैं, तो संक्षिप्तता को अनदेखा करने से बचें:

ctx, cncl := context.WithTimeout(context.Background(), time.Second*3)
defer cncl()

req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://google.com", nil)

resp, _ := http.DefaultClient.Do(req)

1
अतिरिक्त जानकारी: प्रति डॉक्टर, कॉन्टेक्स्ट द्वारा लगाई गई समय सीमा भी शरीर को पढ़ती है, इसी तरह http.Client.Timeout
kubanczyk

1
गो 1.7+ के लिए एक स्वीकृत उत्तर होना चाहिए । जाओ 1.13+ थोड़ा का उपयोग कर छोटा किया जा सकता के लिए NewRequestWithContext
kubanczyk

9

एक त्वरित और गंदा तरीका:

http.DefaultTransport.(*http.Transport).ResponseHeaderTimeout = time.Second * 45

यह वैश्विक स्थिति w / o को किसी भी समन्वय में परिवर्तित कर रहा है। फिर भी यह आपके url भ्रूण के लिए संभवतः ठीक हो सकता है। अन्यथा का एक निजी उदाहरण बनाएँ http.RoundTripper:

var myTransport http.RoundTripper = &http.Transport{
        Proxy:                 http.ProxyFromEnvironment,
        ResponseHeaderTimeout: time.Second * 45,
}

var myClient = &http.Client{Transport: myTransport}

resp, err := myClient.Get(url)
...

ऊपर कुछ भी परीक्षण नहीं किया गया था।


कृपया किसी ने भी मुझे सही किया है, लेकिन ऐसा लगता है कि रिस्पांसहैडरटाइमआउट रीड टाइमआउट के बारे में है, यह कनेक्शन स्थापित होने के बाद का समय समाप्त है। सबसे व्यापक समाधान @dmichael द्वारा एक प्रतीत होता है, क्योंकि यह डायल टाइमआउट और रीड टाइमआउट दोनों को सेट करने की अनुमति देता है।
डेनियल बी

http.DefaultTransport.(*http.Transport).ResponseHeaderTimeout = time.Second * 45अनुरोध टाइमआउट के लिए लिखित परीक्षा में मुझे मदद करें। आपका बहुत बहुत धन्यवाद।
ली


-1
timeout := time.Duration(5 * time.Second)
transport := &http.Transport{Proxy: http.ProxyURL(proxyUrl), ResponseHeaderTimeout:timeout}

यह मदद कर सकता है, लेकिन नोटिस जो ResponseHeaderTimeoutकनेक्शन स्थापित होने के बाद ही शुरू होता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.