Maison > Article > développement back-end > Golang implémente la passerelle API
Avec la popularité de l'architecture des microservices et l'augmentation du nombre de services, afin d'améliorer la sécurité, la fiabilité et l'évolutivité des services, la technologie de passerelle API a émergé au fur et à mesure que les temps l'exigent. Aujourd'hui, nous allons parler de la façon d'utiliser Golang pour écrire une passerelle API.
1. Pourquoi choisir d'utiliser Golang
2. Idées de conception de passerelle API
Avant de concevoir une passerelle API, nous devons savoir ce qu'une passerelle API doit faire. De manière générale, une passerelle API doit effectuer les opérations suivantes :
Selon les idées ci-dessus, nous concevons une passerelle API simple, qui comprend principalement les composants suivants :
3. Implémenter API Gateway
Ensuite, nous implémenterons les composants ci-dessus un par un.
1. Routeur
Pour implémenter un routeur, nous devons d'abord définir un élément de routage :
type Route struct { Path string Method string Handler http.Handler }
Route contient un chemin pour stocker le chemin de routage, une méthode pour stocker le type de méthode de la requête et un gestionnaire. pour stocker et traiter la méthode de demande.
Ensuite, nous définissons une structure de routeur pour stocker la liste de routes et acheminer la demande vers le processeur correspondant :
type Router struct { routes []*Route } func (r *Router) HandleFunc(path string, method string, handlerFunc http.HandlerFunc) { r.routes = append(r.routes, &Route{Path: path, Method: method, Handler: handlerFunc}) } func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { for _, route := range r.routes { if route.Path == req.URL.Path && route.Method == req.Method { route.Handler.ServeHTTP(w, req) return } } http.Error(w, "404 not found", http.StatusNotFound) }
Dans le code, nous fournissons deux méthodes pour enregistrer la méthode de traitement de la demande et la route, HandleFunc devrait être similaire à http.HandleFunc, il lie l'adresse de routage, la méthode de demande et la méthode de traitement de la demande à un objet. ServeHTTP recherchera une route correspondante après avoir reçu la demande, elle transmettra la demande à la méthode de traitement correspondante. Si elle n'est pas trouvée, renverra 404.
Ensuite, écrivez une implémentation simple d'une méthode de traitement :
func main() { router := &Router{} router.HandleFunc("/hello", "GET", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "hello") }) http.ListenAndServe(":8080", router) }
Cette méthode de traitement renverra hello pour toute requête GET avec l'adresse /hello.
2. Filtre
WAF (Web Application Firewall) est un filtre couramment utilisé pour protéger les applications Web contre diverses attaques. Nous pouvons filtrer les demandes en fonction de la méthode de demande, des en-têtes de demande, des paramètres de demande et d'autres informations. Ici, nous utilisons les en-têtes de requête comme filtres. Si l'en-tête de la requête contient une balise spécifique, elle est transmise, sinon elle est considérée comme une requête invalide.
Pour implémenter des filtres à l'aide de Golang, nous devons écrire un middleware qui vérifiera si une balise spécifique est incluse dans chaque requête. S'il est inclus, continuez à transmettre la demande, sinon une erreur sera renvoyée. Nous pouvons utiliser gorilla/mux pour implémenter un middleware.
type FilterMiddleware struct { next http.Handler } func (f *FilterMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Header.Get("X-Auth-Token") != "magic" { http.Error(w, "Unauthorized request", http.StatusUnauthorized) return } f.next.ServeHTTP(w, r) } func (r *Router) RegisterMiddleware(middleware func(http.Handler) http.Handler) { handler := http.Handler(r) for _, m := range middlewareFunctions { handler = m(handler) } r.Handler = handler }
Dans le code, FilterMiddleware vérifiera si l'en-tête de la requête contient la balise "X-Auth-Token". Si c'est le cas, la requête sera transmise, sinon une erreur non autorisée sera renvoyée. Nous définissons également une fonction RegisterMiddleware pour enregistrer le middleware.
3. Équilibrage de charge
L'équilibrage de charge est l'un des composants les plus importants de la passerelle API. Il peut distribuer les requêtes à différentes instances de service sur le backend. Nous pouvons utiliser des algorithmes de sondage, aléatoires et autres pour y parvenir.
Ici, nous utilisons un algorithme d'interrogation simple pour l'équilibrage de charge. Nous pouvons sélectionner l'adresse du serveur suivant dans un pool et transmettre la demande à ce serveur.
type LoadBalancer struct { Pool []string Next int } func (l *LoadBalancer) Pick() string { if l.Next >= len(l.Pool) { l.Next = 0 } host := l.Pool[l.Next] l.Next++ return host } func (r *Router) HandleFunc(path string, method string, handlerFunc http.HandlerFunc) { l := &LoadBalancer{ Pool: []string{"http://127.0.0.1:8081", "http://127.0.0.1:8082"}, Next: 0, } handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { url, err := url.Parse(l.Pick()) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } proxy := httputil.NewSingleHostReverseProxy(url) proxy.ServeHTTP(w, req) }) r.routes = append(r.routes, &Route{Path: path, Method: method, Handler: handler}) }
Dans le code, nous avons créé une structure simple d'équilibrage de charge qui contient le pool de serveurs et l'emplacement du prochain serveur à sélectionner. La méthode pick() sélectionnera une adresse de serveur en fonction de la longueur du pool de serveurs. Dans HandleFunc, nous utilisons l'algorithme Round Robin pour transmettre les requêtes à différents serveurs.
4. Mise en cache
La mise en cache peut améliorer les performances du système et également réduire le nombre de requêtes adressées au backend. Dans la passerelle API, nous pouvons intégrer le cache dans le processus de réponse à la demande et renvoyer directement la demande dans le cache qui peut fournir rapidement une réponse.
type Cache struct { data map[string] []byte mutex sync.Mutex } func (c *Cache) Get(key string) []byte { c.mutex.Lock() defer c.mutex.Unlock() if value, ok := c.data[key]; ok { return value } return nil } func (c *Cache) Set(key string, value []byte) { c.mutex.Lock() defer c.mutex.Unlock() c.data[key] = value } func (r *Router) HandleFunc(path string, method string, handlerFunc http.HandlerFunc) { cache := &Cache{ data: make(map[string][]byte), } handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { key := r.URL.String() if data := cache.Get(key); data != nil { w.Write(data) return } buffer := &bytes.Buffer{} proxy := httputil.NewSingleHostReverseProxy(r.URL) proxy.ServeHTTP(buffer, r) cache.Set(key, buffer.Bytes()) w.Write(buffer.Bytes()) }) r.routes = append(r.routes, &Route{Path: path, Method: method, Handler: handler}) }
Dans le code, nous avons créé une structure de cache et mis en cache la requête dans HandleFunc. Si la même requête existe dans le cache, nous pouvons renvoyer le résultat directement depuis le cache, réduisant ainsi le nombre de requêtes vers le backend.
5. Surveillance
La surveillance peut nous aider à mieux comprendre l'état de fonctionnement du système et à saisir la vitesse de réponse du système actuel, etc.
使用Prometheus来实现API网关的监控。我们只需记录下来每一个请求的响应时间、状态码及信息,然后将所有的数据发送到Prometheus。
var ( apiRequestsDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: "api_request_duration_seconds", Help: "The API request duration distribution", Buckets: prometheus.DefBuckets, }, []string{"status"}) ) type MetricMiddleware struct { next http.Handler } func (m *MetricMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { start := time.Now() ww := httptest.NewRecorder() m.next.ServeHTTP(ww, r) duration := time.Since(start) apiRequestsDuration.WithLabelValues(strconv.Itoa(ww.Code)).Observe(duration.Seconds()) for key, values := range ww.Header() { for _, value := range values { w.Header().Add(key, value) } } w.WriteHeader(ww.Code) body := ww.Body.Bytes() w.Write(body) } func main() { router := &Router{} router.HandleFunc("/hello", "GET", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "hello") }) logger := NewLoggerMiddleware(router) http.Handle("/metrics", prometheus.Handler()) http.Handle("/", logger) service := ":8080" log.Printf("Server starting on %v ", service) log.Fatal(http.ListenAndServe(service, nil)) }
在代码中,我们定义了一个MetricMiddleware并在请求结束后统计相关时间数据,最后通过Prometheus将数据输出到Metrics监控系统中。我们还通过http.Handle将Prometheus绑定在“/metrics”路径上,方便查询。
结束语
至此,我们用Golang实现了一个简单的API网关。在实际使用中,我们还可以添加更多的功能,如熔断、限流、容错等,来提高其安全性、稳定性和可用性。
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!