Master Go Middleware: Build, Modify, and Manage HTTP Handlers

This guide walks through creating Go middleware, showing how to read and modify requests, manage response headers with custom ResponseWriter implementations, handle edge cases like missing Write calls, and preserve additional interfaces such as http.Pusher and http.Flusher.

360 Zhihui Cloud Developer
360 Zhihui Cloud Developer
360 Zhihui Cloud Developer
Master Go Middleware: Build, Modify, and Manage HTTP Handlers

Introduction

Writing middleware in Go may seem easy, but many pitfalls appear in practice. This article demonstrates how to create reusable HTTP middleware components.

1. Read Request

All middleware receive an http.Handler and return an http.Handler. The basic pattern is:

func X(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Something here...
        h.ServeHTTP(w, r)
    })
}

Example: redirect trailing slash.

func TrailingSlashRedirect(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path != "/" && r.URL.Path[len(r.URL.Path)-1] == '/' {
            http.Redirect(w, r, r.URL.Path[:len(r.URL.Path)-1], http.StatusMovedPermanently)
            return
        }
        h.ServeHTTP(w, r)
    })
}

2. Modify Request

To add or change request headers, create a shallow copy of *http.Request and modify the copy before passing it on.

func RequestID(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        r2 := new(http.Request)
        *r2 = *r
        r2.Header.Set("X-Request-Id", uuid.NewV4().String())
        h.ServeHTTP(w, r2)
    })
}

3. Write Response Header

Setting a response header can be done directly, but if downstream handlers also set the same header it may be overwritten. Implement a custom ResponseWriter to control header writing.

type serverWriter struct {
    w            http.ResponseWriter
    name         string
    wroteHeaders bool
}
func (s *serverWriter) Header() http.Header { return s.w.Header() }
func (s *serverWriter) WriteHeader(code int) {
    if !s.wroteHeaders {
        s.w.Header().Set("Server", s.name)
        s.wroteHeaders = true
    }
    s.w.WriteHeader(code)
}
func (s *serverWriter) Write(b []byte) (int, error) {
    if !s.wroteHeaders {
        s.w.Header().Set("Server", s.name)
        s.wroteHeaders = true
    }
    return s.w.Write(b)
}

Middleware using it:

func Server(h http.Handler, servername string) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        sw := &serverWriter{w: w, name: servername}
        h.ServeHTTP(sw, r)
    })
}

Problem

If a handler never calls Write or WriteHeader (e.g., a 200 response with empty body), the custom header may never be set. Adding a check after ServeHTTP ensures the header is written.

Other ResponseWriter Interfaces

The ResponseWriter may also implement interfaces such as http.Pusher or http.Flusher. Forwarding these methods preserves HTTP/2 support and flushing behavior.

// Push implements http.Pusher
func (s *serverWriter) Push(target string, opts *http.PushOptions) error {
    if pusher, ok := s.w.(http.Pusher); ok {
        return pusher.Push(target, opts)
    }
    return http.ErrNotSupported
}
// Flush implements http.Flusher
func (s *serverWriter) Flush() {
    if f, ok := s.w.(http.Flusher); ok {
        f.Flush()
    }
}

Summary

The article provides a complete overview of building Go middleware, covering request reading, modification, response header handling, and preserving additional interfaces.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

middlewareHTTPServer
360 Zhihui Cloud Developer
Written by

360 Zhihui Cloud Developer

360 Zhihui Cloud is an enterprise open service platform that aims to "aggregate data value and empower an intelligent future," leveraging 360's extensive product and technology resources to deliver platform services to customers.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.