Dekoratör olarak Middleware
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 97 / 107.
Middleware, Go'da Dekoratör kalıbının en pratik uygulamalarından biridir. Web geliştirmede middleware işlevleri, özgün işleyiciyi değiştirmeden günlük kaydı, kimlik doğrulama veya zamanlama gibi kesişen konular eklemek için HTTP işleyicilerini sarar.
Temel fikir, ara yazılımın bir işleyici alıp eklenmiş davranışa sahip yeni bir işleyici döndürmesidir. Bu, Decorator desenini tam olarak izler: girişte ve çıkışta aynı arayüz, geliştirilmiş işlevsellikle birlikte:
type Handler func(request string) string
func LoggingMiddleware(next Handler) Handler {
return func(request string) string {
result := next(request)
return "[LOG] " + result
}
}
func AuthMiddleware(next Handler) Handler {
return func(request string) string {
return "[AUTH] " + next(request)
}
}Her bir ara yazılım, zincirdeki bir sonraki işleyiciyi sarar ve sarılmış işleyiciyi çağırmadan önce veya çağırdıktan sonra kendi davranışını ekler. Birden fazla ara yazılımı birleştirerek üst üste ekleyebilirsiniz:
func MainHandler(request string) string {
return "Response to: " + request
}
handler := LoggingMiddleware(AuthMiddleware(MainHandler))
fmt.Println(handler("GET /users"))
// [LOG] [AUTH] Response to: GET /usersSarmalama sırası, yürütme sırasını belirler: en dıştaki ara yazılım ilk olarak çalışır. Bu desen, istek işleme işlem hatları için Go web çatılarında yaygın olarak kullanılır ve temel işleyici mantığına dokunmadan işlevsellik eklemeyi veya kaldırmayı kolaylaştırır.
Görev
KolayMiddleware as Decorator desenini kullanarak bir istek işleme hattı oluşturalım! Middleware işlevlerinin, temel işleyici mantığını değiştirmeden zamanlama, doğrulama ve biçimlendirme gibi işlevler eklemek için işleyicileri sardığı bir sistem oluşturacaksın.
Kodunu üç dosya arasında düzenleyeceksin:
handler.go: İşleyici türünü ve istekleri işleyen temel işleyiciyi tanımla.Bir istek dizesi alan ve bir yanıt dizesi döndüren bir işlev olarak
Handlertürü oluştur:type Handler func(request string) stringAldığı her istek için
BaseHandlerdöndüren birProcessed: [request]işlevi uygula.middleware.go: İşleyicileri ek davranışlarla saran middleware işlevlerini oluştur.Her biri bir
Handleralan ve yeni birHandlerdöndüren üç middleware işlevi oluştur:TimingMiddleware: yanıta zamanlama bilgisi ekleyerek[TIMING] [response]döndürürValidationMiddleware: doğrulama öneki ekleyerek[VALID] [response]döndürürUppercaseMiddleware: yanıtın tamamını büyük harfe dönüştürür
Her middleware, sardığı işleyiciyi çağırmalı ve sonucunu geliştirmelidir.
main.go: Middleware'leri birleştirerek bir işleme hattı oluştur.Uygulanacak middleware katmanlarının sayısını oku. Ardından her katman için middleware türünü (
timing,validationveyauppercase) oku ve mevcut işleyicini bu middleware ile sar. Middleware'leri okundukları sırayla uygula: okunan ilk middleware en dıştaki sarmalayıcı olur.İşleme hattını oluşturduktan sonra istek dizesini oku, oluşturduğun işleyici üzerinden işle ve sonucu yazdır.
Aşağıdaki girdiler sağlanacaktır:
- 1. satır: Middleware katmanlarının sayısı
- Sonraki satırlar: Her satırda bir middleware türü (
timing,validationveyauppercase) - Son satır: İşlenecek istek
Örneğin, şu giriş verildiğinde:
2
timing
validation
GET /usersÇıktın şöyle olmalıdır:
[TIMING] [VALID] Processed: GET /usersVe şu giriş verildiğinde:
3
uppercase
timing
validation
POST /dataÇıktın şöyle olmalıdır:
[TIMING] [VALID] PROCESSED: POST /DATAVe şu giriş verildiğinde:
1
uppercase
hello worldÇıktın şöyle olmalıdır:
PROCESSED: HELLO WORLDVe şu giriş verildiğinde:
0
simple requestÇıktın şöyle olmalıdır:
Processed: simple requestMiddleware sarmalama sırasının çıktıyı nasıl etkilediğine dikkat et: uygulanan ilk middleware (en dıştaki) önce çalışır ve tüm iç middleware'lerden gelen nihai sonucu görür. İkinci örnekteki uppercase middleware'i en son (en içte) çalışır; bu nedenle timing ve validation öneklerini eklemeden önce temel yanıtı büyük harfe dönüştürür!
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Middleware katmanlarının sayısını oku
nLine, _ := reader.ReadString('\n')
n, _ := strconv.Atoi(strings.TrimSpace(nLine))
// Middleware türlerini oku
middlewareTypes := make([]string, n)
for i := 0; i < n; i++ {
line, _ := reader.ReadString('\n')
middlewareTypes[i] = strings.TrimSpace(line)
}
// İsteği oku
request, _ := reader.ReadString('\n')
request = strings.TrimSpace(request)
// TODO: BaseHandler ile başla
// TODO: Handler'ı middleware ile sararak pipeline'ı oluştur
// Middleware'leri sırayla uygula - okunan ilk middleware en dış sarmalayıcı olur
// İpucu: Bunu başarmak için middlewareTypes üzerinde TERS sırada döngü yap
// Uygulanan son middleware en dıştaki olacaktır (ilk çalışır)
// TODO: İsteği birleştirilmiş handler üzerinden işle ve sonucu yazdır
fmt.Println("TODO: implement pipeline")
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı11Standart Kütüphane ve OOP
io.Reader ve io.Writersort.Interface Arayüzüfmt.Stringer ArayüzüStruct'lar ile encoding/jsonhttp.Handler ArayüzüÖzet - REST API Modelleri14Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıDekoratör olarak Middleware3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker PoolKendi başına pratik yap: Online Go derleyicisi