# Reverse proxy

## Reverse proxy simple

[GitHub repo](https://github.com/Nouuu/go-gin-training/tree/main/reverse_proxy)

Le reverse proxy est quelque chose de majoritairement utilisé aujourd'hui.

Dans beaucoup de cas d'utilisation, on utilise des outils tels que Nginx, Apache, Caddy uniquement pour faire du reverse proxy.

Mais avec **Gin**, on peut coder ça soit même !

**Contexte :**

- Notre serveur **Gin** écoute en local sur le port 8080
- Mon serveur portainer tourne en local et écoute sur le port 9000
- Je veux qu’en me connectant sur mon serveur **Gin**, ce dernier me fasse un reverse proxy sur mon serveur portainer.

Dans mon fichier `main.go`, nous allons déclarer l’URL de mon reverse proxy ainsi qu’une méthode `proxy` qui sera la méthode utilisée par **Gin**

```go
package main

import "github.com/gin-gonic/gin"

const reverseServerAddr = "http://127.0.0.1:9000"

func proxy(c *gin.Context) {

}

func main() {
	
}

```

Nous dire à notre routeur **Gin**, que TOUTES les requêtes, et ce, peu importe la méthode, doit utiliser notre fameuse méthode `func proxy(c *gin.Context)`.

```go
func main() {
	router := gin.Default()

	router.Any("/*any", proxy)

	router.Run(":8080")
}

```

- `router.Any` signifie que quelle que soit la méthode (GET, POST, PUT, ...) utilisé, elle sera pris en charge.
- `/*any` est une expression indiquant à **Gin** que la route peut être n’importe quoi

---

Nous allons maintenant nous attaquer à la méthode `func proxy(c *gin.context)` qui va dans un premier temps parser notre URL de destination (la variable `reverseServerAddr`) avec la librairie `net/url` :

```go
func proxy(c *gin.Context) {

	proxy, err := url.Parse(reverseServerAddr)
	if err != nil {
		fmt.Printf("Error parsing reverse proxy address: %s\n", err)
		c.IndentedJSON(http.StatusInternalServerError, gin.H{
			"message": "Error parsing reverse proxy address",
			"error":   err.Error(),
		})
		return
	}

}

```

On gère bien évidement le cas d’erreur où on n’arriverait pas à parser correctement cette URL et on gère le renvoie d’une erreur au client, on arrête également la méthode avec `return`.

La variable `proxy` sera du type `*url.URL`.

Il suffit ensuite d’extraire la requête de notre contexte `c *gin.Context` et modifier son chemin ainsi que son protocole par celui de notre `proxy`.

```go
func proxy(c *gin.Context) {
	
	...

	req := c.Request
	req.URL.Scheme = proxy.Scheme
	req.URL.Host = proxy.Host
}

```

Notre requête est prête, nous allons maintenant l’exécuter et récupérer son retour

```go
func proxy(c *gin.Context) {
	
	...

	transport := http.DefaultTransport
	resp, err := transport.RoundTrip(req)
	if err != nil {
		fmt.Printf("Error making request: %s\n", err)
		c.IndentedJSON(http.StatusInternalServerError, gin.H{
			"message": "Error making request",
			"error":   err.Error(),
		})
		return
	}

}

```

Là encore, si une erreur survient, on la dirige correctement et on met fin à l’exécution de la méthode.

- `http.DefaultTransport`
- `transport.RoundTrip(req)`

Ce sont des méthodes de la librairie `net/http` et permettent d’exécuter une seule requête web.

Maintenant que la requête a été effectuée et que son retour est récupéré, il faut maintenant la donner à notre réponse et notre reverse proxy sera complet.

```go
func proxy(c *gin.Context) {
	
	...

	for headerKey, headerValues := range resp.Header {
		for _, headerValue := range headerValues {
			c.Header(headerKey, headerValue)
		}
	}
	defer resp.Body.Close()
	bufio.NewReader(resp.Body).WriteTo(c.Writer)
	return
}

```

Ce que nous faisons ici est :

- Nous récupèrerons l'en-tête de notre réponse et les passons à notre contexte (notre vraie réponse).
- Nous passons le body de notre réponse à celui de notre retour aussi.

---

C’est partit pour tester tout ça !

On lance notre application et on se rend sur notre adresse `localhost:8080`

![Untitled](https://images2.imgbox.com/bd/08/N3s6QwH8_o.png)

![Untitled](https://images2.imgbox.com/8b/25/VOv5x2rn_o.png)

![Untitled](https://images2.imgbox.com/1f/cb/SMqEqXMt_o.png)

## Load Balancer

[Surprise ....](https://github.com/Nouuu/go-gin-training/tree/main/reverse_proxy_load_balancer)