Responsive golang webapp without JavaScript
tl;dr
It is possible to flush the http.ResponseWriter
with the help of http.Flusher
and create a responsive feedback for users that dont have JavaScript enabled.
Introduction
Recently I developed a mini website that has a database backend with a search form.
The website should be usable for users that do not have JavaScript enabled (Crazy right? ;-)), so no rest API, and no fancy JavaScript frameworks.
I noticed that the search function could take some time, and most of the users (nowadays) expect pages to load instantly.
Thus, it can happen that some users start clicking the search button over and over again, resulting in aborting the current request and asking for a new search. This can lead to massive io overload, since one user triggers (accidently) multiple searches.
Of course we can limit the resources per user, to avoid multiple search instances, however the ux is still horrible.
I wanted something that notifies the user that the search is actually happening.
Disabling the button
Well I could disable the button as soon as the user clicks it, or display a spinner or something similar. However this will likely reqire JavaScript…
Responding directly with a page
The best solution for me is to send a ‘i am working’ page directly after the user triggers the search and keeping the connection open, this allowes me to send an update as soon as the search is done. This update message can be used to hide the working dialog and display the search results.
http.Flusher
By using http.Flusher
it is possible to directly flush the contents:
func workHandler(w http.ResponseWriter, req *http.Request) {
var flusher http.Flusher
if f, ok := w.(http.Flusher); ok {
flusher = f
}
w.Write([]byte("I am working\n"))
if flusher != nil {
flusher.Flush()
}
time.Sleep(1000 * time.Millisecond)
w.Write([]byte("Still working...\n"))
if flusher != nil {
flusher.Flush()
}
w.Write([]byte("I am done"))
}
This allows us to send the header first, maybe some information about the progress a bit later, and the results on the end.
With some CSS it is also possible to show a progressbar, done so in the sample project you can find here.