Click the above“blue text” to follow us
Middleware Design Patterns in Go: 8 Common Interception Techniques for HTTP Request Handling
“Boss, we have repeated the login validation logic in our system over a dozen times, and the code is everywhere!” Little Wang, who just joined a few days ago, ran over with a frown and a notebook. Look at this situation, it seems he is encountering this problem for the first time. I smiled and said: “Duplicate code is a big taboo, Little Wang! Today, Brother Feng will teach you how to solve this problem using Go middleware.”
Middleware sounds impressive, but it is essentially an intermediary that handles HTTP requests. It can quietly do some tasks before the request reaches your business logic or before the response returns to the client. For example, verifying user identity, logging access, detecting malicious requests… These common functionalities can be handled by middleware, making it reusable everywhere, which is great!
1.
The Essence of Middleware: Onion Model
The essence of Go middleware is essentially a chain of functions. Imagine an onion, where the request cuts in from the outside to the inside like a knife, and then cuts out from the inside to the outside, with each layer of “onion skin” being a middleware.
The Most Basic Middleware looks like this:
func Logger(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now() next.ServeHTTP(w, r) fmt.Printf(“Request processing took: %s
”, time.Since(start))
}) }
Did you understand? This is just a “wrapper function” that adds some functionality around the original handler function, both before and after.
2.
Practical Middleware Techniques
1. Authorization Middleware
Authorization is probably the most commonly used middleware. Place it at the outermost layer to block illegal visitors, simple and efficient!
func Auth(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get(“Authorization”) if !isValidToken(token) { http.Error(w, “Unauthorized access”, http.StatusUnauthorized) return // Directly intercept here, will not call the next handler } next.ServeHTTP(w, r)
}) }
What’s the key? It’s in the<span>return</span>
line! If you don’t call<span>next.ServeHTTP</span>
, the request won’t reach the next stage, just like a security guard stopping someone without an ID card.
2. Recovery Middleware
Code can go wrong, and life can too. But we can’t let the server crash directly! Check this out:
func Recovery(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() { if err := recover(); err != nil { log.Printf(“Program panic: %v”, err) http.Error(w, “Internal server error”, 500) } }() next.ServeHTTP(w, r)
}) }
This is like installing an airbag in the system; even if the code crashes, the user will only see a friendly error message instead of a confused complaint of “the system crashed again.”
3.
Advanced Middleware Techniques
If you want to improve the performance and maintainability of your Go service, these techniques are essential:
Request Traceability. Assign a unique ID to each request to link all logs, a debugging tool.
Response Compression. Large text responses? Use gzip middleware to automatically compress, saving half the network traffic!
Rate Limiting. Prevent API from being overwhelmed, limit the number of requests per second, simple and practical.
Response Time Monitoring. Which API is lagging? A simple statistic will tell you.
If you want to become an API optimization expert, starting with these middlewares is definitely the right choice.
4.
Pitfall Reminders
Middleware is a double-edged sword. Used well, it can be very effective; used poorly, it can ruin performance! A few points to note:
Order Matters. The authentication middleware should be at the outermost layer, while the compression middleware should be at the innermost layer. If the order is reversed, it may waste resources on compression while authentication fails.
Less is More. The more middlewares there are, the more layers each request has to traverse, naturally increasing latency. Only add what is truly needed; don’t pile on features just for aesthetics.
Be Mindful of Resource Release. Opened files in middleware? Created connections? Remember to close them! Otherwise, resource leaks can cause the server to crash in no time.
The design of middleware in Go is simple and elegant, just like the philosophy of the Go language itself. Mastering this skill will lead to a qualitative leap in code quality and system performance. Even in interviews, this is a plus point. Little Wang, have you learned? Next time you see duplicate code, think about whether you can solve it with middleware!
Practice makes perfect; try writing a few middlewares. Don’t be afraid of encountering problems; that’s proof of growth. Brother Feng is waiting for your good news!