Welcome to a comprehensive guide on using the Go Context in HTTP Servers! In this lesson, we'll cover everything from the basics to advanced examples, making it suitable for both beginners and intermediates. Let's dive in!
Context is a powerful feature in Go that allows for propagating values across multiple function calls, making it easier to manage timeouts, cancellations, and other request-scoped values.
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
select {
case <-time.After(time.Second):
fmt.Println("One second passed")
case <-ctx.Done():
fmt.Println("Context timed out")
}
}In the above example, we create a context with a timeout of 5 seconds and execute two select cases. If the one-second timeout passes, we print "One second passed". If the context times out before that, we print "Context timed out".
Now, let's see how we can apply the Context to HTTP servers to manage requests effectively.
package main
import (
"context"
"fmt"
"net/http"
"time"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
defer cancel()
select {
case <-time.After(time.Second):
fmt.Fprint(w, "One second passed")
case <-ctx.Done():
fmt.Fprint(w, "Context timed out")
w.WriteHeader(http.StatusGatewayTimeOut)
}
})
http.ListenAndServe(":8080", nil)
}In this example, we create an HTTP server that responds to any request with either "One second passed" or "Context timed out" based on the context timeout.
Now, let's make our server more practical by creating a route that performs an expensive operation and uses context for cancellation.
package main
import (
"context"
"fmt"
"net/http"
"time"
)
func longTask(ctx context.Context) {
select {
case <-ctx.Done():
fmt.Println("Task cancelled")
return
default:
// Simulate an expensive operation
time.Sleep(10 * time.Second)
fmt.Println("Task completed")
}
}
func handler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(r.Context())
go longTask(ctx)
// Simulate a user clicking a cancel button
if r.URL.Path == "/cancel" {
cancel()
}
fmt.Fprint(w, "Request received")
}
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/cancel", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Cancelling task...")
})
http.ListenAndServe(":8080", nil)
}In this example, we create an HTTP server with a route that starts a long-running task. We also create another route for cancelling the task if needed.
What does the `WithTimeout` function do in Go's Context package?