Rumah > Artikel > pembangunan bahagian belakang > golang melaksanakan pintu masuk api
Dengan populariti seni bina perkhidmatan mikro dan peningkatan dalam bilangan perkhidmatan, untuk meningkatkan keselamatan, kebolehpercayaan dan kebolehskalaan perkhidmatan, teknologi get laluan API telah muncul mengikut keperluan masa. Hari ini kita akan bercakap tentang cara menggunakan Golang untuk menulis get laluan API.
1. Mengapa memilih untuk menggunakan Golang
2. Idea reka bentuk get laluan API
Sebelum mereka bentuk get laluan API, kita perlu tahu perkara yang perlu dilakukan oleh get laluan API. Secara umumnya, get laluan API perlu melakukan perkara berikut:
Menurut idea di atas, kami mereka bentuk get laluan API yang ringkas, yang terutamanya merangkumi komponen berikut:
3. Laksanakan API Gateway
Seterusnya kita akan melaksanakan komponen di atas satu persatu.
1. Penghala
Untuk melaksanakan penghala, kita perlu mentakrifkan item penghalaan terlebih dahulu:
type Route struct { Path string Method string Handler http.Handler }
Laluan mengandungi Laluan untuk menyimpan laluan penghalaan dan Kaedah untuk menyimpan Jenis kaedah permintaan, Pengendali digunakan untuk menyimpan kaedah untuk memproses permintaan.
Seterusnya kami mentakrifkan struktur Penghala untuk menyimpan senarai laluan dan menghalakan permintaan ke pemproses yang sepadan:
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) }
Dalam kod, kami menyediakan dua kaedah untuk pendaftaran Permintaan kaedah pemprosesan dan penghalaan harus serupa dengan http.HandleFunc Ia akan mengikat alamat penghalaan, kaedah permintaan dan kaedah pemprosesan permintaan kepada objek ServeHTTP akan mencari laluan yang sepadan selepas menerima permintaan tersebut kaedah, dan 404 dikembalikan jika tidak dijumpai.
Seterusnya, tulis pelaksanaan kaedah pemprosesan mudah:
func main() { router := &Router{} router.HandleFunc("/hello", "GET", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "hello") }) http.ListenAndServe(":8080", router) }
Kaedah pemprosesan ini akan membalas hello untuk sebarang permintaan GET dengan alamat /hello.
2. Penapis
WAF (Web Application Firewall) ialah penapis yang biasa digunakan untuk melindungi aplikasi web daripada pelbagai serangan. Kami boleh menapis permintaan berdasarkan kaedah permintaan, pengepala permintaan, parameter permintaan dan maklumat lain. Di sini, kami menggunakan pengepala permintaan sebagai penapis. Jika pengepala permintaan mengandungi teg tertentu, ia diluluskan, jika tidak, ia dianggap sebagai permintaan tidak sah.
Untuk melaksanakan penapis menggunakan Golang, kami perlu menulis perisian tengah yang akan menyemak sama ada teg tertentu disertakan dalam setiap permintaan. Jika ia disertakan, teruskan turunkan permintaan, jika tidak ralat akan dikembalikan. Kita boleh menggunakan gorila/mux untuk melaksanakan 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 }
Dalam kod, FilterMiddleware akan menyemak sama ada pengepala permintaan mengandungi teg "X-Auth-Token" Jika ya, permintaan itu akan diturunkan, jika tidak, ralat yang tidak dibenarkan akan dikembalikan. Kami juga mentakrifkan fungsi RegisterMiddleware untuk mendaftar middleware.
3. Pengimbangan beban
Pengimbangan beban ialah salah satu komponen terpenting dalam get laluan API Ia boleh mengedarkan permintaan kepada contoh perkhidmatan yang berbeza pada bahagian belakang. Kita boleh menggunakan algoritma pengundian, rawak dan lain-lain untuk mencapai ini.
Di sini kami menggunakan algoritma tinjauan pendapat mudah untuk pengimbangan beban. Kami boleh memilih alamat pelayan seterusnya dari kumpulan dan memajukan permintaan ke pelayan itu.
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}) }
Dalam kod, kami mencipta struktur pengimbangan beban mudah yang mengandungi kumpulan pelayan dan lokasi pelayan seterusnya yang akan dipilih. Kaedah pick() akan memilih alamat pelayan berdasarkan panjang kumpulan pelayan. Dalam HandleFunc, kami menggunakan algoritma Round Robin untuk memajukan permintaan ke pelayan yang berbeza.
4. Caching
Caching boleh meningkatkan prestasi sistem dan juga mengurangkan bilangan permintaan ke bahagian belakang. Dalam get laluan API, kami boleh membenamkan cache dalam proses respons permintaan dan terus mengembalikan permintaan dalam cache yang boleh memberikan respons dengan cepat.
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}) }
Dalam kod, kami mencipta struktur cache dan cache permintaan dalam HandleFunc. Jika permintaan yang sama wujud dalam cache, kami boleh mengembalikan hasil terus daripada cache, sekali gus mengurangkan bilangan permintaan ke bahagian belakang.
5. Pemantauan
Pemantauan boleh membantu kami memahami dengan lebih baik status pengendalian sistem dan memahami kelajuan tindak balas sistem semasa.
使用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网关。在实际使用中,我们还可以添加更多的功能,如熔断、限流、容错等,来提高其安全性、稳定性和可用性。
Atas ialah kandungan terperinci golang melaksanakan pintu masuk api. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!