Exploring Lesser-Known HTTP Handlers in Go
When working with Go’s net/http
package, most of us are familiar with the basics: http.HandleFunc
for routing, http.ServeMux
for handling multiple routes, and http.FileServer
for serving static files. But Go’s HTTP package has a few lesser-known handlers and functions that can be incredibly useful for more specific needs. Let’s dive into these often-overlooked features and see how they can make your life easier.
1. http.HandlerFunc
One of the simplest yet powerful tools is http.HandlerFunc
. It allows you to create an HTTP handler from a regular function. If you have a small function that handles a request, you can use http.HandlerFunc
to convert it into a handler.
Example:
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, World!")
})
In this example, any request to /hello
will receive "Hello, World!" as a response.
2. http.ServeMux
When you need to handle multiple routes, http.ServeMux
(or simply ServeMux
) is your go-to. It matches the URL of incoming requests against a list of registered patterns and directs them to the appropriate handlers.
Example:
mux := http.NewServeMux()
mux.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Foo handler")
})
mux.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Bar handler")
})
http.ListenAndServe(":8080", mux)
Here, requests to /foo
will be handled by one function, and requests to /bar
by another.
3. http.NotFoundHandler
Sometimes, you want a specific handler for 404 errors (page not found). http.NotFoundHandler
provides a simple way to handle these errors.
Example:
http.Handle("/404", http.NotFoundHandler())
This handler will return a 404 status code for any request to /404
.
4. http.RedirectHandler
Need to redirect requests to a different URL? http.RedirectHandler
is perfect for that. It helps set up URL redirections with the specified status code.
Example:
http.Handle("/redirect", http.RedirectHandler("https://example.com", http.StatusMovedPermanently))
Here, requests to /redirect
will be permanently redirected to "https://example.com".
5. http.FileServer
Serving static files is a common requirement. http.FileServer
makes it easy to serve files from a directory.
Example:
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
Requests to /static/
will be served with files from the ./static
directory.
6. http.ServeFile
For serving a single file directly from a handler, use http.ServeFile
. It’s straightforward and handy for specific file-serving needs.
Example:
func fileHandler(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "path/to/file")
}
This will serve the file located at "path/to/file" in response to any request handled by fileHandler
.
7. http.ServeContent
If you need to serve content with specific headers, http.ServeContent
is a versatile tool. It lets you serve content with additional headers like Content-Type
or Content-Disposition
.
Example:
func contentHandler(w http.ResponseWriter, r *http.Request) {
content := []byte("This is some content")
http.ServeContent(w, r, "filename.txt", time.Now(), bytes.NewReader(content))
}
This serves a piece of content with the filename "filename.txt" and current timestamp.
8. http.Handler
For more complex scenarios, you might implement the http.Handler
interface. This interface requires a single method, ServeHTTP
, which you can use to define custom request handling logic.
Example:
type myHandler struct{}
func (h *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Custom handler")
}
http.Handle("/custom", &myHandler{})
Requests to /custom
will be handled by myHandler
, which writes "Custom handler" to the response.
9. http.DefaultServeMux
The DefaultServeMux
is a default multiplexer provided by Go. If you don’t provide a custom multiplexer, Go uses this one by default.
Example:
http.HandleFunc("/default", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Default handler")
})
http.ListenAndServe(":8080", nil) // Uses DefaultServeMux
This sets up a default handler for /default
using Go’s built-in multiplexer.
10. http.TimeoutHandler
If you want to set a timeout for a handler, http.TimeoutHandler
can wrap an existing handler and specify a timeout duration.
Example:
handler := http.TimeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(5 * time.Second) // Simulate a slow handler
fmt.Fprintln(w, "Slow handler")
}), 2*time.Second, "Timeout")
http.Handle("/timeout", handler)
Here, if the handler takes more than 2 seconds, it will return a timeout error.
11. http.Pusher
For HTTP/2 applications, http.Pusher
allows you to push resources to the client. This feature is not a handler itself but can be used to optimize loading times by preemptively sending resources.
Example:
func handler(w http.ResponseWriter, r *http.Request) {
pusher, ok := w.(http.Pusher)
if !ok {
http.Error(w, "Push not supported", http.StatusInternalServerError)
return
}
if err := pusher.Push("/styles.css", nil); err != nil {
fmt.Printf("Failed to push: %v", err)
}
fmt.Fprintln(w, "Content with push")
}
http.HandleFunc("/", handler)
This example attempts to push a CSS file to the client along with the main content.
Wrapping Up
These lesser-known HTTP handlers in Go offer powerful ways to handle requests and responses. Whether you're managing static files, implementing custom request handling, or optimizing performance with HTTP/2 features, these tools can help you build more efficient and effective web applications. Exploring and using these features can add more flexibility and control to your Go web projects.
Subscribe to my newsletter
Read articles from Sachin Borse directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by