Cliente HTTP em Go: fazendo requisições corretamente de A a Z
Go (Golang) é uma linguagem conhecida por sua simplicidade e desempenho, especialmente na área de programação de redes. O pacote embutido net/http fornece um cliente HTTP poderoso e flexível, adequado tanto para requisições simples quanto para sistemas complexos de alta carga. Neste artigo, vamos analisar como usar corretamente o cliente HTTP em Go, desde requisições básicas até configurações avançadas.
1. Fundamentos: criando e executando requisições simples
A maneira mais simples de fazer uma requisição HTTP em Go é usar as funções auxiliares do pacote net/http, como http.Get e http.Post. No entanto, para código de produção, recomenda-se criar explicitamente o cliente e a requisição.
Requisição GET básica:
package main
import ( "fmt" "io/ioutil" "net/http")
func main() { // Cria um novo cliente client := &http.Client{}
// Cria a requisição req, err := http.NewRequest("GET", "https://api.example.com/data", nil) if err != nil { fmt.Println("Erro ao criar requisição:", err) return }
// Executa a requisição resp, err := client.Do(req) if err != nil { fmt.Println("Erro ao executar requisição:", err) return } defer resp.Body.Close()
// Lê o corpo da resposta body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("Erro ao ler resposta:", err) return }
fmt.Println("Status:", resp.Status) fmt.Println("Corpo:", string(body))}Requisição POST com corpo JSON:
package main
import ( "bytes" "encoding/json" "fmt" "net/http")
type Payload struct { Name string `json:"name"` Email string `json:"email"`}
func main() { payload := Payload{Name: "John", Email: "john@example.com"} jsonData, _ := json.Marshal(payload)
client := &http.Client{} req, err := http.NewRequest("POST", "https://api.example.com/users", bytes.NewBuffer(jsonData)) if err != nil { fmt.Println("Erro:", err) return }
// Define os cabeçalhos req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer your-token")
resp, err := client.Do(req) if err != nil { fmt.Println("Erro:", err) return } defer resp.Body.Close()
fmt.Println("Status:", resp.Status)}2. Gerenciamento de timeouts e contextos
Um dos erros mais comuns é a falta de timeouts. Sem eles, seu cliente pode travar por tempo indeterminado, aguardando uma resposta do servidor. Em Go, existem duas maneiras principais de gerenciar o tempo de espera.
Timeout no nível do cliente:
client := &http.Client{ Timeout: 10 * time.Second, // Timeout total para toda a requisição}Timeout usando contexto (recomendado):
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.example.com/data", nil)if err != nil { log.Fatal(err)}
resp, err := client.Do(req)if err != nil { // Verifica se o timeout expirou if errors.Is(err, context.DeadlineExceeded) { fmt.Println("Requisição excedeu o timeout") } else { fmt.Println("Erro:", err) } return}defer resp.Body.Close()O uso de contexto oferece mais flexibilidade: você pode cancelar a requisição a qualquer momento (por exemplo, ao fechar o aplicativo) e transmitir valores através do contexto.
3. Tratamento de erros e tentativas repetidas
A rede não é confiável, portanto, seu cliente deve estar preparado para falhas temporárias.