Java 如何强制浏览器下载文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6520231/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to force browser to download file?
提问by dieeying
Everything works fine, but only if file is small, about 1MB, when I tried it with bigger files, like 20MB my browser display it, instead of force to download, I tried many headers so far, now my code looks:
一切正常,但前提是文件很小,大约 1MB,当我尝试使用更大的文件时,比如 20MB,我的浏览器显示它,而不是强制下载,到目前为止我尝试了很多标题,现在我的代码看起来:
PrintWriter out = response.getWriter();
String fileName = request.getParameter("filename");
File f= new File(fileName);
InputStream in = new FileInputStream(f);
BufferedInputStream bin = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bin);
while(din.available() > 0){
out.print(din.readLine());
out.print("\n");
}
response.setContentType("application/force-download");
response.setContentLength((int)f.length());
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Disposition","attachment; filename=\"" + "xxx\"");//fileName);
in.close();
bin.close();
din.close();
采纳答案by Vineet Reynolds
You are setting the response headers after writing the contents of the file to the output stream. This is quite late in the response lifecycle to be setting headers. The correct sequence of operations should be to set the headers first, and then write the contents of the file to the servlet's outputstream.
在将文件内容写入输出流后,您正在设置响应标头。在响应生命周期中设置标头已经很晚了。正确的操作顺序应该是先设置头,然后将文件内容写入servlet的输出流。
Therefore, your method should be written as follows (this won't compile as it is a mere representation):
因此,你的方法应该写成如下(这不会编译,因为它只是一个表示):
response.setContentType("application/force-download");
response.setContentLength((int)f.length());
//response.setContentLength(-1);
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Disposition","attachment; filename=\"" + "xxx\"");//fileName);
...
...
File f= new File(fileName);
InputStream in = new FileInputStream(f);
BufferedInputStream bin = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bin);
while(din.available() > 0){
out.print(din.readLine());
out.print("\n");
}
The reason for the failure is that it is possible for the actual headers sent by the servlet would be different from what you are intending to send. After all, if the servlet container does not know what headers (which appear before the body in the HTTP response), then it may set appropriate headers to ensure that the response is valid; setting the headers after the file has been written is therefore futile and redundant as the container might have already set the headers. You could confirm this by looking at the network traffic using Wireshark or a HTTP debugging proxy like Fiddler or WebScarab.
失败的原因是 servlet 发送的实际头可能与您打算发送的不同。毕竟,如果 servlet 容器不知道什么 headers(在 HTTP 响应中出现在 body 之前),那么它可能会设置适当的 headers 以确保响应是有效的;因此,在写入文件后设置标头是徒劳且多余的,因为容器可能已经设置了标头。您可以通过使用 Wireshark 或 HTTP 调试代理(如 Fiddler 或 WebScarab)查看网络流量来确认这一点。
You may also refer to the Java EE API documentation for ServletResponse.setContentTypeto understand this behavior:
您还可以参考ServletResponse.setContentType的 Java EE API 文档以了解此行为:
Sets the content type of the response being sent to the client, if the response has not been committed yet.The given content type may include a character encoding specification, for example, text/html;charset=UTF-8. The response's character encoding is only set from the given content type if this method is called before getWriter is called.
This method may be called repeatedly to change content type and character encoding. This method has no effect if called after the response has been committed.
...
如果响应尚未提交,则设置发送到客户端的响应的内容类型。给定的内容类型可以包括字符编码规范,例如 text/html;charset=UTF-8。如果在调用 getWriter 之前调用此方法,则响应的字符编码仅从给定的内容类型设置。
可能会重复调用此方法以更改内容类型和字符编码。如果在响应提交后调用此方法,则此方法无效。
...
回答by f1sh
This is from a php script which solves the problem perfectly with every browser I've tested (FF since 3.5, IE8+, Chrome)
这是来自一个 php 脚本,它完美地解决了我测试过的每个浏览器的问题(FF 自 3.5、IE8+、Chrome)
header("Content-Disposition: attachment; filename=\"".$fname_local."\"");
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($fname));
So as far as I can see, you're doing everything correctly. Have you checked your browser settings?
所以据我所知,你做的一切都是正确的。你检查过你的浏览器设置吗?
回答by Vladimir Dyuzhev
Set content-type and other headers beforeyou write the file out. For small files the content is buffered, and the browser gets the headers first. For big ones the data come first.
在写出文件之前设置内容类型和其他标题。对于小文件,内容被缓冲,浏览器首先获取标题。对于大公司,数据是第一位的。