I feel I have tried everything short of changing application to use AJAX and returning responses with JSON instead of rendering new HTML page as I do now (using Go's https://github.com/unrolled/render package) - it will be A LOT of work to redo everything, so I hope that there's a solution that doesn't involve AJAX + JSON response.
Right now, whenever I do a form POST, at the end I render a new HTML page as such:
render.HTML(w, http.StatusOK, "path/to/htmlfile/index", map[string]interface{}{
csrf.TemplateTag: csrf.TemplateField(r),
"passing some data": dataFromGo})
This works perfectly both locally and in production, BUT the moment I put it inside an iframe, then whenever I click the form submit the page becomes blank (white) for 1-2 seconds before the new HTML page is rendered (whereas when accessed without iframe then the original HTML content will remain displayed while waiting for the new content to be rendered). I feel it's really strange that this behavior only happens inside the iframe.
Is there any solution to this? I have tried setting <iframe name="my-iframe" ..>
and in my form set target="my-iframe"
, I have tried adding sandbox
to the iframe. I have tried other things that in hindsight were completely irrelevant to solving my problem :)
By the way, the iframe src is another domain, but this is unavoidable
From my experiments, it looks like browsers turn the iframe white as soon as the first byte of the response body arrives. My guess is that your own code or the render package sends bytes before the actual processing is done. You can see the behaviour with this sample program:
package main
import (
"fmt"
"log"
"net/http"
"time"
)
func main() {
http.DefaultServeMux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "text/html")
fmt.Fprintln(w, `<iframe src="/frame"></iframe>`)
}))
http.DefaultServeMux.Handle("/frame/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "text/html")
// Remove either of the following two calls and the iframe doesn't turn white.
fmt.Fprint(w, " ")
w.(http.Flusher).Flush()
time.Sleep(2 * time.Second) // Lots of work to do...
fmt.Fprint(w, `
<form style="background:red" method="post">
<button>submit</button>
</form>
`)
}))
log.Fatal(http.ListenAndServe(":4000", nil))
}
Remove the flush or the first write, and the iframe stays rendered pretty much all the time. Why this behaviour is different from the top document is beyond me.
I'm not familiar with github.com/unrolled/render. See if there are writes that can be deferred until the end, or if you can buffer the response (body) before sending it down the wire.