如何在下载文件时使客户端打开保存文件对话框

huangapple go评论121阅读模式
英文:

How to make client open save file dialog when downloading a file

问题

我希望浏览器在用户点击下载文件按钮时,显示或打开一个文件保存对话框来保存我发送的文件。

我的服务器端下载代码:

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()

    // 复制相关的头部信息。如果你想保留下载文件的名称,可以使用Go的URL解析器提取它。
    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()
    // 将响应体流式传输给客户端,而不完全加载到内存中
    io.Copy(w, resp.Body)
}

请注意,这是一个用Go语言编写的服务器端代码,用于处理文件下载。它从指定的URL下载文件,并将文件流式传输给客户端。在这段代码中,我们设置了响应头部信息,以便浏览器能够正确地处理文件下载。

英文:

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)
}

答案1

得分: 5

如果你希望响应保存在客户端,可以使用"attachment"内容分发类型。这在rfc2183的第2.2节中有详细说明:

2.2 附件分发类型

Bodyparts可以被指定为attachment,以表示它们与邮件消息的主体分开,并且它们的显示不应该是自动的,而是取决于用户的进一步操作。MUA可以为具有位图终端的用户提供附件的图标表示,或者在字符终端上提供附件列表,用户可以选择查看或存储。

所以设置如下:

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

此外,在设置响应写入器w的头部时,复制你所做的响应的字段,而不是来自传入请求的字段:

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

还要注意,头部更像是对浏览器的一个“建议”。你可以建议响应是一个要保存的文件,但是从服务器端你无法强制浏览器真正将响应保存为文件而不是显示它。

参考相关问题:https://stackoverflow.com/questions/31018042/golang-beego-output-to-csv-file-dumps-the-data-to-browser-but-not-dump-to-file/31019074#31019074

英文:

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: https://stackoverflow.com/questions/31018042/golang-beego-output-to-csv-file-dumps-the-data-to-browser-but-not-dump-to-file/31019074#31019074

huangapple
  • 本文由 发表于 2017年7月6日 16:11:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/44943267.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定