Ontwerp en Implementeer Middleware in Go voor Webapplicaties
description
Met deze prompt leer je hoe je middleware effectief inzet in Go-webapplicaties om herbruikbare en beheerbare code te schrijven voor gemeenschappelijke taken als logging en beveiliging. Dit voorkomt duplicatie en verbetert onderhoudbaarheid en veiligheid, wat lastig te bereiken is zonder middleware.
prompt
Help mij met het ontwerpen en implementeren van middleware in Go voor mijn webapplicatie. Leg uit hoe ik middleware inzet voor taken zoals logging, authenticatie en fou ...
try_prompt
generate_helper
disclaimerOnPageApi
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een overzicht en voorbeeldcode voor het ontwerpen en implementeren van middleware in Go met het `net/http` pakket. Middleware wordt gebruikt om functies zoals logging, authenticatie en foutafhandeling aan je request-verwerking toe te voegen op een gestructureerde manier.
### Structuur van Middleware in Go
In Go wordt middleware vaak geïmplementeerd als een functie die een `http.Handler` neemt en een nieuwe `http.Handler` retourneert. Dit stelt je in staat om meerdere middleware achter elkaar te koppelen.
### Basis structuur
```go
type Middleware func(http.Handler) http.Handler
```
### Voorbeeld: Middleware functies
1. **Logging Middleware**
```go
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("Started %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
log.Printf("Completed %s in %v", r.URL.Path, time.Since(start))
})
}
```
2. **Authenticatie Middleware**
```go
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if token != "Bearer mijnsecrettoken" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
```
3. **Foutafhandelings Middleware**
Deze middleware kan de response opvangen en aanpassen bij fouten, bijvoorbeeld door een gestandaardiseerd formaat te gebruiken.
```go
func RecoveryMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("Panic: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}()
next.ServeHTTP(w, r)
})
}
```
### Middleware koppelen
Om meerdere middleware te gebruiken, kun je ze achter elkaar aan roepen:
```go
func ChainMiddleware(handler http.Handler, middlewares ...Middleware) http.Handler {
for _, m := range middlewares {
handler = m(handler)
}
return handler
}
```
### Voorbeeld hoofdprogramma
```go
package main
import (
"log"
"net/http"
"time"
)
// Middleware functies hier (zoals hierboven)
// hoofd handler
func HelloHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hallo, wereld!"))
}
func main() {
// Basis handler
baseHandler := http.HandlerFunc(HelloHandler)
// Middleware keten
handler := ChainMiddleware(baseHandler,
RecoveryMiddleware,
LoggingMiddleware,
AuthMiddleware,
)
http.Handle("/", handler)
log.Println("Server gestart op :8080")
http.ListenAndServe(":8080", nil)
}
```
### Samenvatting
- Middleware in `net/http` wordt geïmplementeerd als functies die `http.Handler` omwikkelen.
- Je kunt meerdere middleware achter elkaar gebruiken door ze te chainen.
- Gebruik middleware voor logging, authenticatie, foutafhandeling, etc.
- Deze aanpak houdt je code overzichtelijk en herbruikbaar.
Wil je dat ik de code verder uitbreid of een specifiek voorbeeld uitwerk?
provider: deepseek
model: deepseek-chat
Zeker! Ik leg uit hoe je middleware kunt ontwerpen en implementeren in Go met het `net/http` package.
## Basisstructuur van Middleware
Middleware in Go is een functie die een `http.Handler` accepteert en een nieuwe `http.Handler` retourneert:
```go
type Middleware func(http.Handler) http.Handler
```
## Algemene Applicatiestructuur
```go
package main
import (
"log"
"net/http"
"time"
)
func main() {
mux := http.NewServeMux()
// Routes
mux.HandleFunc("/", homeHandler)
mux.HandleFunc("/api/protected", protectedHandler)
// Middleware chain
handler := chainMiddleware(
mux,
loggingMiddleware,
authMiddleware,
errorHandlingMiddleware,
)
log.Println("Server gestart op :8080")
http.ListenAndServe(":8080", handler)
}
func chainMiddleware(h http.Handler, middlewares ...Middleware) http.Handler {
for _, middleware := range middlewares {
h = middleware(h)
}
return h
}
```
## 1. Logging Middleware
```go
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// Wrap de ResponseWriter om status code te kunnen lezen
wrapped := &responseWriter{w, http.StatusOK}
next.ServeHTTP(wrapped, r)
duration := time.Since(start)
log.Printf("%s %s %d %v", r.Method, r.URL.Path, wrapped.status, duration)
})
}
type responseWriter struct {
http.ResponseWriter
status int
}
func (rw *responseWriter) WriteHeader(code int) {
rw.status = code
rw.ResponseWriter.WriteHeader(code)
}
```
## 2. Authenticatie Middleware
```go
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if token == "" {
http.Error(w, "Unauthorized: Geen token aangeboden", http.StatusUnauthorized)
return
}
// Simpele token validatie (vervang dit met echte authenticatie)
if !isValidToken(token) {
http.Error(w, "Unauthorized: Ongeldig token", http.StatusUnauthorized)
return
}
// Voeg gebruikerinfo toe aan context
user := getUserFromToken(token)
ctx := context.WithValue(r.Context(), "user", user)
r = r.WithContext(ctx)
next.ServeHTTP(w, r)
})
}
func isValidToken(token string) bool {
// Implementeer echte token validatie
return token == "valid-token-123"
}
func getUserFromToken(token string) string {
// Haal gebruikerinfo uit token
return "gebruiker@example.com"
}
```
## 3. Foutafhandeling Middleware
```go
func errorHandlingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("Panic opgevangen: %v", err)
http.Error(w, "Interne serverfout", http.StatusInternalServerError)
}
}()
next.ServeHTTP(w, r)
})
}
```
## 4. CORS Middleware (Extra voorbeeld)
```go
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
```
## Voorbeeld Handlers
```go
func homeHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Welkom bij de home pagina!"))
}
func protectedHandler(w http.ResponseWriter, r *http.Request) {
// Haal gebruiker uit context
user := r.Context().Value("user").(string)
w.Write([]byte("Beveiligde content voor: " + user))
}
```
## Alternatieve Aanpak met Struct
Je kunt ook een middleware struct maken voor complexere scenario's:
```go
type App struct {
middleware []Middleware
router *http.ServeMux
}
func NewApp() *App {
return &App{
router: http.NewServeMux(),
}
}
func (a *App) Use(middleware Middleware) {
a.middleware = append(a.middleware, middleware)
}
func (a *App) HandleFunc(pattern string, handler http.HandlerFunc) {
a.router.HandleFunc(pattern, handler)
}
func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var handler http.Handler = a.router
for i := len(a.middleware) - 1; i >= 0; i-- {
handler = a.middleware[i](handler)
}
handler.ServeHTTP(w, r)
}
```
## Gebruik van de Struct Aanpak
```go
func main() {
app := NewApp()
app.Use(loggingMiddleware)
app.Use(authMiddleware)
app.Use(errorHandlingMiddleware)
app.HandleFunc("/", homeHandler)
app.HandleFunc("/api/data", dataHandler)
http.ListenAndServe(":8080", app)
}
```
## Belangrijke Punten:
1. **Volgorde matters**: Middleware wordt uitgevoerd in de volgorde waarin ze worden toegevoegd
2. **Context gebruiken**: Gebruik context voor het doorgeven van data tussen middleware
3. **Error handling**: Zorg voor goede foutafhandeling in elke middleware
4. **Performance**: Middleware voegt overhead toe, houd het lichtgewicht
Deze aanpak geeft je een flexibele en schaalbare middleware-structuur voor je Go webapplicatie!