How to download file in browser from Go server

前端 未结 3 1767
走了就别回头了
走了就别回头了 2020-12-12 18:24

My code get file from remote url and download file in browser:

func Index(w http.ResponseWriter, r *http.Request) {
    url := \"http://upload.wikimedia.org/         


        
相关标签:
3条回答
  • 2020-12-12 18:53

    What you need to use is the Content-Disposition header with attachment value. MDN web docs says the following about the header:

    [...], the Content-Disposition response header is a header indicating if the content is expected to be displayed inline in the browser, that is, as a Web page or as part of a Web page, or as an attachment, that is downloaded and saved locally.

    If you want to specify a filename for the clients you can use the filename directive. In the following format:

    Content-Disposition: attachment; filename="filename.jpg"
    

    This is an optional parameter and it has some restrictions.

    [...] The filename is always optional and must not be used blindly by the application: path information should be stripped, and conversion to the server file system rules should be done. [...]

    To format filename properly in the header you should use mime.FormatMediaType. Example:

    cd := mime.FormatMediaType("attachment", map[string]string{"filename": d.Name()})
    w.Header().Set("Content-Disposition", cd)
    

    In this case for content type you can use application/octet-stream because the browser does not have to know the MIME type of the response.

    [...] Generic binary data (or binary data whose true type is unknown) is application/octet-stream. [...]

    w.Header().Set("Content-Type", "application/octet-stream")
    

    For outputing the content of a. file I would recommend to use http.ServeContent or http.ServeFile because they handle RFC 7233 - Range Requests out of the box. Example:

    f, err := fs.Open(name)
    // [...]
    cd := mime.FormatMediaType("attachment", map[string]string{"filename": d.Name()})
    w.Header().Set("Content-Disposition", cd)
    w.Header().Set("Content-Type", "application/octet-stream")
    http.ServeContent(w, r, d.Name(), d.ModTime(), f)
    
    0 讨论(0)
  • 2020-12-12 18:57

    In case you already have the file on disk, just use http.ServeFile(). It automatically handles Content-Length so that the browser can display a download progress.

    w.Header().Set("Content-Disposition", "attachment; filename="+strconv.Quote(filename))
    w.Header().Set("Content-Type", "application/octet-stream")
    http.ServeFile(w, r, filePath)
    
    0 讨论(0)
  • 2020-12-12 19:04

    To make the browser open the download dialog, add a Content-Disposition and Content-Type headers to the response:

    w.Header().Set("Content-Disposition", "attachment; filename=WHATEVER_YOU_WANT")
    w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
    

    Do this BEFORE sending the content to the client. You might also want to copy the Content-Length header of the response to the client, to show proper progress.

    To stream the response body to the client without fully loading it into memory (for big files this is important) - simply copy the body reader to the response writer:

    io.Copy(w, resp.Body)
    

    io.Copy is a nice little function that take a reader interface and writer interface, reads data from one and writes it to the other. Very useful for this kind of stuff!

    I've modified your code to do this: http://play.golang.org/p/v9IAu2Xu3_

    0 讨论(0)
提交回复
热议问题