2

I want the browser to show or open a file save dialog box to save the file I send when user clicks on the download file button.

My server side code for download:

func Download(w http.ResponseWriter, r *http.Request) {
    url := "http://upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png"

    timeout := time.Duration(5) * time.Second
    transport := &http.Transport{
        ResponseHeaderTimeout: timeout,
        Dial: func(network, addr string) (net.Conn, error) {
            return net.DialTimeout(network, addr, timeout)
        },
        DisableKeepAlives: true,
    }
    client := &http.Client{
        Transport: transport,
    }
    resp, err := client.Get(url)
    if err != nil {
        fmt.Println(err)
    }
    defer resp.Body.Close()

    //copy the relevant headers. If you want to preserve the downloaded file name, extract it with go's url parser.
    w.Header().Set("Content-Disposition", "form-data; filename=Wiki.png")
    w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
    w.Header().Set("Content-Length", r.Header.Get("Content-Length"))
    //dialog.File().Filter("XML files", "xml").Title("Export to XML").Save()
    //stream the body to the client without fully loading it into memory
    io.Copy(w, resp.Body)
}
icza
  • 389,944
  • 63
  • 907
  • 827
cuong
  • 31
  • 4

1 Answers1

5

If you intend the response to be saved at the client side, use the "attachment" content disposition type. This is detailed in rfc2183, section 2.2:

2.2 The Attachment Disposition Type

Bodyparts can be designated `attachment' to indicate that they are separate from the main body of the mail message, and that their display should not be automatic, but contingent upon some further action of the user. The MUA might instead present the user of a bitmap terminal with an iconic representation of the attachments, or, on character terminals, with a list of attachments from which the user could select for viewing or storage.

So set it like this:

w.Header().Set("Content-Disposition", "attachment; filename=Wiki.png")

Also when setting headers of your response writer w, copy the fields from the response you make, not from the incoming request:

w.Header().Set("Content-Type", resp.Header.Get("Content-Type"))
w.Header().Set("Content-Length", resp.Header.Get("Content-Length"))

Also note that the headers are more like a "proposal" to the browser. That's one thing you suggest the response is a file to be saved, but from the server side you can't force the browser to really save the response to a file and not display it.

See related question: Golang beego output to csv file dumps the data to browser but not dump to file

icza
  • 389,944
  • 63
  • 907
  • 827
  • 1
    Not work for me, I use chrome to download. With IE, the default is to allow the directory to save the download. I'm understanding that it depends on the browser – cuong Jul 06 '17 at 08:43
  • "Not work for me" --- explain what that means. What you see and what you expect to see? – zerkms Jul 06 '17 at 10:04
  • My expectation is that after click button download, then open dialog select a folder to save the file.But I understand that in addition to code implementation, you need settings to be able to open the browser dialog. Thank you! – cuong Jul 06 '17 at 10:45