我的代码从远程网址获取文件并在浏览器中下载文件:
func Index(w http.ResponseWriter, r *http.Request) {
url := "http://upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png"
...
resp, err := client.Get(url)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
fmt.Println(len(body))
//download the file in browser
}
func main() {
http.HandleFunc("/", Index)
err := http.ListenAndServe(":8000", nil)
if err != nil {
fmt.Println(err)
}
}
代码:http://play.golang.org/p/x-EyR2zFjv
获取文件没问题,但如何在浏览器中下载?
感谢。
答案 0 :(得分:52)
要使浏览器打开下载对话框,请在回复中添加Content-Disposition
和Content-Type
标题:
w.Header().Set("Content-Disposition", "attachment; filename=WHATEVER_YOU_WANT")
w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
在将内容发送到客户端之前执行此操作。您可能还希望将响应的Content-Length
标头复制到客户端,以显示正确的进度。
要将响应主体流式传输到客户端而不将其完全加载到内存中(对于大文件,这很重要) - 只需将主体阅读器复制到响应编写器:
io.Copy(w, resp.Body)
io.Copy
是一个很好的小函数,它采用读取器接口和编写器接口,从一个读取数据并将其写入另一个。对这种东西非常有用!
我已修改您的代码以执行此操作:http://play.golang.org/p/v9IAu2Xu3_
答案 1 :(得分:2)
如果文件已经在磁盘上,请使用http.ServeFile()。它会自动处理Content-Length
,以便浏览器可以显示下载进度。
w.Header().Set("Content-Disposition", "attachment; filename="+strconv.Quote(filename))
w.Header().Set("Content-Type", "application/octet-stream")
http.ServeFile(w, r, filePath)
答案 2 :(得分:0)
您需要使用带有attachment
值的Content-Disposition
标头。 MDN Web文档对标头说了以下内容:
[...],
Content-Disposition
响应标头是标头,指示是否希望在浏览器中内联显示内容,即以网页或网页形式显示。网页的一部分,或作为附件,已在本地下载并保存。
如果要为客户端指定文件名,则可以使用filename指令。采用以下格式:
Content-Disposition: attachment; filename="filename.jpg"
这是一个可选参数,它有一些限制。
[...]文件名始终是可选的,并且不能被应用程序盲目使用:路径信息应被删除,并且应完成向服务器文件系统规则的转换。 [...]
要在标题中正确格式化文件名,应使用mime.FormatMediaType
。示例:
cd := mime.FormatMediaType("attachment", map[string]string{"filename": d.Name()})
w.Header().Set("Content-Disposition", cd)
在这种情况下,对于内容类型,您可以使用application/octet-stream
,因为浏览器不必知道响应的MIME type。
[...]通用二进制数据(或真实类型未知的二进制数据)是application / octet-stream。 [...]
w.Header().Set("Content-Type", "application/octet-stream")
用于输出a的内容。我建议使用http.ServeContent
或http.ServeFile
这个文件,因为它们开箱即用地处理RFC 7233 - Range Requests。示例:
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)