Introduction : Pourquoi il est important de savoir travailler avec HTTP en Go
\nGo (Golang) est un langage conçu pour le travail en réseau. Sa bibliothèque standard net/http fournit des outils puissants et flexibles pour créer à la fois des serveurs et des clients. Cependant, de nombreux développeurs, surtout ceux venant de langages de script, commettent des erreurs typiques : ils oublient de fermer le corps de la réponse, ne définissent pas de timeouts ou gèrent incorrectement les erreurs.
Dans cet article, nous allons détailler la création d'un client HTTP en Go « de A à Z ». Vous apprendrez à envoyer correctement des requêtes GET et POST, à gérer les en-têtes, à configurer les timeouts et à traiter les erreurs. Tous les exemples de code sont prêts à l'emploi.
\n\n1. Bases : création du client et première requête GET
\nEn Go, le client HTTP est une structure http.Client. Vous pouvez utiliser le client global http.DefaultClient ou créer le vôtre avec des paramètres personnalisés. Commençons par une simple requête GET.
package main\n\nimport (\n "fmt"\n "io"\n "net/http"\n "os"\n)\n\nfunc main() {\n // Utilisation du client intégré\n resp, err := http.Get("https://api.example.com/data")\n if err != nil {\n fmt.Printf("Erreur de requête : %v\\n", err)\n os.Exit(1)\n }\n defer resp.Body.Close() // IMPORTANT : toujours fermer le corps de la réponse !\n\n // Lecture du corps de la réponse\n body, err := io.ReadAll(resp.Body)\n if err != nil {\n fmt.Printf("Erreur de lecture de la réponse : %v\\n", err)\n os.Exit(1)\n }\n\n fmt.Printf("Statut : %s\\n", resp.Status)\n fmt.Printf("Corps : %s\\n", string(body))\n}\nPoints clés :
\n- \n
- Fermez toujours
resp.Bodyavecdefer. Sinon, une fuite de ressources se produit (les connexions ne retournent pas dans le pool). \n - Vérifiez le statut de la réponse (
resp.StatusCode). Le code 200 n'est pas le seul succès (il y a 201, 204, etc.). \n io.ReadAlllit tout le corps en mémoire. Pour les grandes réponses, utilisezio.Copyou un traitement par flux. \n
2. Client avancé : timeouts, en-têtes et paramètres personnalisés
\nLe client global n'a pas de timeouts par défaut — cela peut entraîner le blocage du programme. Créez toujours votre propre client avec des paramètres.
\n2.1. Création d'un client avec timeout
\nclient := &http.Client{\n Timeout: 10 * time.Second, // Timeout global pour toute la requête\n}\n\nresp, err := client.Get("https://api.example.com/data")\nVous pouvez également configurer des timeouts à différents niveaux via Transport :
transport := &http.Transport{\n DialContext: (&net.Dialer{\n Timeout: 5 * time.Second, // Timeout de connexion\n KeepAlive: 30 * time.Second,\n }).DialContext,\n TLSHandshakeTimeout: 5 * time.Second,\n ResponseHeaderTimeout: 5 * time.Second,\n}\n\nclient := &http.Client{\n Transport: transport,\n Timeout: 15 * time.Second,\n}\n\n2.2. Ajout d'en-têtes et de paramètres
\nPour les requêtes complexes, utilisez http.NewRequest :
req, err := http.NewRequest("GET", "https://api.example.com/search", nil)\nif err != nil {\n log.Fatal(err)\n}\n\n// Ajout d'en-têtes\nreq.Header.Set("Authorization", "Bearer your-token")\nreq.Header.Set("Accept", "application/json")\n\n// Ajout de paramètres de requête\nq := req.URL.Query()\nq.Add("query", "golang")\nq.Add("page", "1")\nreq.URL.RawQuery = q.Encode()\n\nresp, err := client.Do(req)\n\n3. Travail avec POST et autres méthodes (JSON, formulaires)
\nLes requêtes POST nécessitent l'envoi d'un corps. Examinons deux formats populaires : JSON et formulaire URL-encodé.
\n3.1. POST avec JSON
\ntype RequestData struct {\n Name string `json:"name"`\n Email string `json:"email"`\n}\n\ndata := RequestData{\n Name: "Ivan",\n Email: "ivan@example.com",\n}\n\njsonData, err := json.Marshal(da