Sling Academy
Home/Golang/How to set timeout when sending HTTP requests in Go

How to set timeout when sending HTTP requests in Go

Last updated: November 27, 2024

When working with HTTP requests in Go, it's important to set a timeout to prevent your application from waiting indefinitely for a response. A timeout ensures that your application can recover or handle the situation gracefully in case of network issues or unresponsive servers.

Using net/http Client Timeout

In Go, the http.Client has a Timeout field that can be used to set a deadline for the entire HTTP request.

package main

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

func main() {
    client := &http.Client{
        Timeout: 10 * time.Second, // Set request timeout to 10 seconds
    }

    resp, err := client.Get("https://www.example.com")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()

    fmt.Println("Response received with status code:", resp.StatusCode)
}

In this example, we create an http.Client and specify a 10-second timeout. If the request takes longer, it will return an error.

Dial and TLS Handshake Timeouts

To set more specific timeouts, you can customize the http.Transport. This is useful when you want to have separate timeouts for establishing a connection, writing the request, and getting the response headers.

package main

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

func main() {
    transport := &http.Transport{
        DialContext: (&net.Dialer{
            Timeout: 5 * time.Second, // Maximum time allowed to establish a connection
        }).DialContext,
        TLSHandshakeTimeout: 5 * time.Second, // Max time for TLS handshake
    }

    client := &http.Client{
        Transport: transport,
        Timeout: 10 * time.Second, // Overall timeout for request
    }

    resp, err := client.Get("https://www.example.com")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()

    fmt.Println("Response received with status code:", resp.StatusCode)
}

Here, the DialContext and TLSHandshakeTimeout ensure that connecting to the server and completing the TLS handshake each has a maximum duration of 5 seconds.

Custom Timeout Using Context Package

For even more control, especially when dealing with complex requests involving multiple parts or different timeouts for different parts, you can use the context package to set a deadline or timeout for requests.

package main

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

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    req, err := http.NewRequestWithContext(ctx, "GET", "https://www.example.com", nil)
    if err != nil {
        fmt.Println("Error creating request:", err)
        return
    }

    client := &http.Client{}

    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error executing request:", err)
        return
    }
    defer resp.Body.Close()

    fmt.Println("Response received with status code:", resp.StatusCode)
}

Using the context package, you can provide a 5-second timeout for this HTTP request. The NewRequestWithContext function is used to attach the context to the request. This method is versatile and can be adjusted for multiple operations or even completely different timeout policies for each request.

Conclusion

Setting appropriate timeouts for HTTP requests is essential for robust and responsive applications. Using http.Client with a Timeout field, customizing transport settings, or using the context package provides flexibility for different scenarios. Always consider the nature of your HTTP interactions to set optimal timeout values that suit your application's needs.

Next Article: How to handle network errors in Go: A deep dive

Previous Article: How to create a simple proxy server with Go

Series: Networking and Server

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant