Changed request handling

This commit is contained in:
Laurent Ulrich 2025-01-27 10:11:01 +01:00
parent 89f4e92d2a
commit 3ad84eb465
1 changed files with 58 additions and 20 deletions

View File

@ -2,78 +2,116 @@ package main
import ( import (
"fmt" "fmt"
"io/ioutil" "io"
"log" "log"
"net/http" "net/http"
"os"
"strings"
"sync" "sync"
) )
var backends = []string{ var backends []string
"http://backend1.local/api",
"http://backend2.local/api",
"http://backend3.local/api",
}
func forwardRequestToBackend(wg *sync.WaitGroup, client *http.Client, backend string, req *http.Request, responses chan<- string) { func forwardRequestToBackend(wg *sync.WaitGroup, client *http.Client, backend string, req *http.Request, responses chan<- string) {
defer wg.Done() defer wg.Done()
// Recréer la requête HTTP /* Recreate the request with same Method, path,query and Body, but to the specified backend */
forwardReq, err := http.NewRequest(req.Method, backend, req.Body) forwardReq, err := http.NewRequest(req.Method, backend, req.Body)
if err != nil { if err != nil {
log.Printf("Error creating request for %s: %v", backend, err) log.Printf("Error creating request for %s: %v", backend, err)
responses <- fmt.Sprintf("Error: %v", err) responses <- fmt.Sprintf("Failed: %v", err)
return return
} }
// Copier les en-têtes de la requête originale // Override Host with original Host
forwardReq.Host = req.Host
// Override RequestURI
forwardReq.RequestURI = req.RequestURI
// Add original headers
forwardReq.Header = req.Header.Clone() forwardReq.Header = req.Header.Clone()
// Envoyer la requête au backend // Send request
resp, err := client.Do(forwardReq) resp, err := client.Do(forwardReq)
if err != nil { if err != nil {
log.Printf("Error forwarding to %s: %v", backend, err) log.Printf("Error forwarding to %s: %v", backend, err)
responses <- fmt.Sprintf("Error: %v", err) responses <- fmt.Sprintf("%s failed: %v", err)
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
// Lire la réponse du backend // Read response body
body, err := ioutil.ReadAll(resp.Body) body, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
log.Printf("Error reading response from %s: %v", backend, err) log.Printf("Error reading response from %s: %v", backend, err)
responses <- fmt.Sprintf("Error: %v", err) responses <- fmt.Sprintf("%s failed: %v", backend, err)
return return
} }
// Ajouter la réponse dans le canal // Ajouter la réponse dans le canal
responses <- fmt.Sprintf("Response from %s: %s", backend, body) responses <- fmt.Sprintf("%s succeeded", backend)
} }
/*
* Take incoming request and make a new request for each backend in a new goroutine.
* In response to origin request send a report sucess or failure with HTTP code.
*/
func handler(w http.ResponseWriter, req *http.Request) { func handler(w http.ResponseWriter, req *http.Request) {
client := &http.Client{} client := &http.Client{}
var wg sync.WaitGroup var wg sync.WaitGroup
responses := make(chan string, len(backends)) responses := make(chan string, len(backends))
// Forward la requête vers chaque backend
for _, backend := range backends { for _, backend := range backends {
wg.Add(1) wg.Add(1)
go forwardRequestToBackend(&wg, client, backend, req, responses) go forwardRequestToBackend(&wg, client, backend, req, responses)
} }
// Attendre la fin de toutes les requêtes
wg.Wait() wg.Wait()
close(responses) close(responses)
// Collecter et afficher les réponses des backends
for response := range responses { for response := range responses {
fmt.Fprintf(w, "%s\n", response) fmt.Fprintf(w, "%s\n", response)
} }
} }
/*
* Just print incoming request elements
*/
func debugHandler(w http.ResponseWriter, req *http.Request) {
backend := "127.0.0.1:8080"
/* Recreate the request with same Method, path,query and Body, but to the specified backend */
backendRequest := fmt.Sprintf("http://%s%s", backend, req.RequestURI)
fmt.Println("Backend Request", ":", backendRequest)
forwardReq, err := http.NewRequest(req.Method, backendRequest, req.Body)
if err != nil {
log.Printf("Error creating request for %s: %v", backend, err)
return
}
forwardReq.Host = req.Host
forwardReq.RequestURI = req.RequestURI
forwardReq.Header = req.Header.Clone()
fmt.Printf("%#v\n", req)
fmt.Printf("%#v\n", forwardReq)
}
func main() { func main() {
http.HandleFunc("/", handler) backendsStr := os.Getenv("BACKENDS")
listenAddress := os.Getenv("LISTEN")
if len(listenAddress) == 0 {
listenAddress = ":8080"
}
if len(backendsStr) == 0 {
log.Println("BACKENDS environment var not defined or empty (BACKENDS=IP:PORT,IP:PORT)")
log.Println("Running as debugger")
http.HandleFunc("/", debugHandler)
} else {
backends = strings.Split(backendsStr, ",")
http.HandleFunc("/", handler)
}
fmt.Println("Starting server on :8080...") fmt.Println("Starting server on :8080...")
if err := http.ListenAndServe(":8080", nil); err != nil { if err := http.ListenAndServe(listenAddress, nil); err != nil {
log.Fatalf("Server failed: %v", err) log.Fatalf("Server failed: %v", err)
} }
} }