One way would be to do your additional work which is not required for the response in another goroutine:
func someHandler(w http.ResponseWriter, r *http.Request) {
go func() {
// Do anything here, this won't delay the response
// But don't touch the writer or request, as they may not be available here
}()
if err := json.NewEncoder(w).Encode("some data"); err != nil {
log.Printf("Error sending response: %v", err)
}
}
Note that in the launched gorotuine you can't use the http.ResponseWriter
nor the http.Request
, as they are only valid to use until you return from your handler. If you need something from them, you must make a copy of the needed parts before you launch the goroutine.
If you want to complete the additional task before you return from the handler, you can still use a goroutine, and use a sync.WaitGroup
to wait for it to complete and only then return from the handler. You may or may not flush the response:
func someHandler(w http.ResponseWriter, r *http.Request) {
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
// You may use the writer and request here
}()
if err := json.NewEncoder(w).Encode("some data"); err != nil {
log.Printf("Error sending response: %v", err)
}
// Optionally you may flush the data written so far (icnluding HTTP headers)
if flusher, ok := w.(http.Flusher); ok {
flusher.Flush()
}
wg.Wait()
}
Note that here the goroutine is allowed to use the http.ResponseWriter
and http.Request
, because the handler does not return until the additional task is completed.