Maison  >  Article  >  développement back-end  >  Comment implémenter l'anti-proxy dans Golang

Comment implémenter l'anti-proxy dans Golang

PHPz
PHPzoriginal
2023-04-25 09:11:361927parcourir

Golang est un langage de programmation efficace et concis. Sa puissante prise en charge de la concurrence et sa vitesse de compilation rapide le rendent largement respecté dans le domaine de la programmation réseau. Un proxy inverse est une architecture réseau commune qui transmet les requêtes à différents serveurs pour optimiser le trafic réseau et améliorer les performances du système. Dans cet article, nous verrons comment implémenter un proxy inverse à l'aide de Golang.

  1. Qu'est-ce qu'un proxy inverse ?

Un proxy inverse est une architecture réseau qui transmet les requêtes des clients à un serveur backend puis renvoie la réponse au client. Contrairement à un proxy direct, un proxy inverse masque l'identité du serveur principal et fournit des services supplémentaires au client, tels que l'équilibrage de charge, la mise en cache et des améliorations de sécurité.

Le cœur du proxy inverse est l’équilibrage de charge. Lorsqu'un client lance une requête auprès du proxy inverse, celui-ci distribue la requête au serveur principal le plus approprié pour maximiser l'efficacité et les performances du réseau. De plus, les proxys inverses peuvent réduire la charge du serveur grâce à la mise en cache et peuvent fournir des fonctionnalités telles que la terminaison SSL et des pare-feu pour améliorer la sécurité du réseau.

  1. Utiliser Golang pour implémenter le proxy inverse

Utiliser Golang pour implémenter le proxy inverse est très simple. Golang fournit une bibliothèque standard "net/http/httputil", qui contient des fonctions et des structures utiles permettant d'implémenter facilement un proxy inverse.

Voici un exemple simple de proxy inverse Golang :

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
)

func main() {
    proxy := httputil.NewSingleHostReverseProxy(&url.URL{
        Scheme: "http",
        Host:   "localhost:8080",
    })
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        proxy.ServeHTTP(w, r)
    })
    log.Fatal(http.ListenAndServe(":3000", nil))
}

Dans cet exemple, nous utilisons la fonction httputil.NewSingleHostReverseProxy pour créer un objet proxy inverse et transmettre la requête au port 8080 de l'hôte local. Nous utilisons ensuite la fonction http.HandleFunc pour associer la fonction de gestionnaire au chemin "/" et démarrons le proxy inverse sur le serveur local au port 3000.

  1. Configuration avancée du proxy inverse

Le proxy inverse créé par le code ci-dessus est très simple, mais dans les applications réelles, nous pouvons avoir besoin d'une configuration plus avancée pour répondre à des besoins spécifiques. Voici quelques exemples de configurations avancées pour les proxy inverses :

  • Équilibrage de charge

L'équilibrage de charge est l'une des fonctions principales d'un proxy inverse. Golang fournit des algorithmes pour répartir uniformément les requêtes entre plusieurs serveurs backend. Voici un exemple simple d'équilibrage de charge :

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
)

func main() {
    backends := []*url.URL{
        &url.URL{
            Scheme: "http",
            Host:   "localhost:8080",
        },
        &url.URL{
            Scheme: "http",
            Host:   "localhost:8081",
        },
        &url.URL{
            Scheme: "http",
            Host:   "localhost:8082",
        },
    }

    proxy := httputil.NewSingleHostReverseProxy(backends[0])
    proxy.Transport = &http.Transport{
        Dial: func(network, address string) (net.Conn, error) {
            return net.DialTimeout(network, address, time.Second)
        },
        MaxIdleConns:        10,
        IdleConnTimeout:     30 * time.Second,
        DisableCompression:  true,
    }

    proxy.ModifyResponse = func(r *http.Response) error {
        r.Header.Set("X-Proxy", "Golang Reverse Proxy")
        return nil
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        i := rand.Intn(len(backends))
        proxy.URL = backends[i]
        proxy.ServeHTTP(w, r)
    })

    log.Fatal(http.ListenAndServe(":3000", nil))
}

Dans cet exemple, nous utilisons un tableau backends avec trois serveurs backend et en sélectionnons un au hasard lorsqu'une requête arrive. Nous avons également configuré une fonction ModifyResponse qui ajoute un en-tête « X-Proxy » aux en-têtes de réponse et utilisé un champ httputil.ReverseProxy.Transport personnalisé pour permettre des propriétés de connexion réseau personnalisées. Enfin, nous avons le serveur proxy inverse qui écoute sur le port local 3000.

  • Résiliation SSL

La résiliation SSL est une technologie qui peut améliorer les performances et la sécurité des sites Web. Un proxy inverse peut servir de point de terminaison SSL, acceptant les requêtes SSL des clients et transmettant les requêtes HTTP non chiffrées au serveur backend. Si votre application utilise le cryptage SSL, cette technologie peut être un excellent moyen de réduire la charge sur le serveur. Voici un exemple simple de terminaison SSL :

package main

import (
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
)

func main() {
    cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
    if err != nil {
        log.Fatalf("Failed to load keypair: %s", err)
    }

    certBytes, err := ioutil.ReadFile("cert.pem")
    if err != nil {
        log.Fatalf("Failed to read cert file: %s", err)
    }

    rootCAs := x509.NewCertPool()
    ok := rootCAs.AppendCertsFromPEM(certBytes)
    if !ok {
        log.Fatal("Failed to append root CA")
    }

    proxy := httputil.NewSingleHostReverseProxy(&url.URL{
        Scheme: "http",
        Host:   "localhost:8080",
    })
    proxy.Transport = &http.Transport{
        TLSClientConfig: &tls.Config{
            Certificates:       []tls.Certificate{cert},
            RootCAs:            rootCAs,
            InsecureSkipVerify: true,
        },
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        proxy.ServeHTTP(w, r)
    })

    log.Fatal(http.ListenAndServeTLS(":3000", "cert.pem", "key.pem", nil))
}

Dans cet exemple, nous utilisons la fonction tls.LoadX509KeyPair pour charger le certificat TLS et la clé privée à partir du système de fichiers et utilisons la fonction x509.NewCertPool pour créer un pool de certificats racine. Nous attribuons ensuite le certificat chargé et le pool de certificats racine au champ httputil.ReverseProxy.Transport.TLSClientConfig pour garantir une connexion sécurisée au client. De plus, nous utilisons la fonction http.ListenAndServeTLS afin de prendre en charge les connexions HTTPS.

  • Caching

La mise en cache est une technologie qui peut améliorer considérablement les performances du proxy inverse. Un proxy inverse peut mettre en cache les ressources statiques frontales, réduisant ainsi la pression sur le serveur. Voici un exemple de cache simple :

package main

import (
    "bytes"
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
    "time"
)

var cache = make(map[string]*bytes.Buffer)

func main() {
    proxy := httputil.NewSingleHostReverseProxy(&url.URL{
        Scheme: "http",
        Host:   "localhost:8080",
    })

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        if r.Method == "GET" {
            if buf, ok := cache[r.URL.Path]; ok {
                w.Write(buf.Bytes())
                return
            }
        }

        if r.Method == "POST" || r.Method == "PUT" || r.Method == "DELETE" {
            delete(cache, r.URL.Path)
        }

        proxy.ServeHTTP(w, r)

        if r.Method == "GET" && r.Header.Get("Cache-Control") != "no-cache" {
            buf := bytes.NewBuffer(nil)
            buf.ReadFrom(w.(http.ResponseWriter))
            cache[r.URL.Path] = buf
        }
    })

    log.Fatal(http.ListenAndServe(":3000", nil))
}

Dans cet exemple, nous utilisons un cache de variables de carte pour stocker les résultats de réponse mis en cache. Lorsque la ressource correspondante existe dans le cache, nous pouvons renvoyer directement le résultat au client sans solliciter le serveur backend. Et nous utilisons le type sous-jacent *bytes.Buffer de l'interface http.ResponseWriter pour mettre en cache les résultats de la réponse. De plus, lorsque la méthode de requête est POST, PUT ou DELETE, nous supprimons le cache afin que les données mises à jour soient récupérées depuis le serveur backend. Enfin, nous déterminons si nous devons mettre en cache le résultat de la réponse en vérifiant le champ "Cache-Control" dans l'en-tête de la requête.

  1. Conclusion

Le proxy inverse est une architecture réseau puissante qui peut améliorer considérablement les performances et la sécurité du système en masquant le serveur principal et en fournissant divers services supplémentaires. Il est très simple de mettre en œuvre un proxy inverse à l'aide de Golang. Golang fournit de nombreuses fonctions et structures utiles pour créer facilement un serveur proxy inverse. Dans cet article, nous avons présenté les concepts de base des proxys inverses et montré comment implémenter différentes configurations de proxys inverses avancés à l'aide de Golang.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn