【问题标题】:How to force browser to download file?如何强制浏览器下载文件?
【发布时间】:2011-09-25 02:26:26
【问题描述】:

一切正常,但只有文件很小,大约 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();

【问题讨论】:

  • 设置内容类型应该可以。是哪个浏览器?
  • 哪个浏览器? Octet-stream 应该是正确的答案,但旧版本的 IE 过去常常尝试“嗅探”内容类型,而不管 Web 服务器告诉它什么
  • chrome、ff 3.6 和其他所有可能...
  • 标题在前,数据在后,而不是其他方式!
  • Content-Disposition 附件会做到这一点。请注意,应用程序/强制下载是某种特定的 hack,而不是标准,请阅读:media-division.com/…

标签: java servlets jakarta-ee


【解决方案1】:

在将文件内容写入输出流后,您正在设置响应标头。在响应生命周期中设置标头已经很晚了。正确的操作顺序应该是先设置headers,再将文件内容写入servlet的outputstream。

因此,你的方法应该写成如下(这不会编译,因为它只是一个表示):

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

失败的原因是 servlet 发送的实际标头可能与您打算发送的不同。毕竟,如果 servlet 容器不知道什么 headers(在 HTTP 响应中出现在 body 之前),那么它可能会设置适当的 headers 以确保响应有效;因此,在文件写入后设置标头是徒劳且多余的,因为容器可能已经设置了标头。您可以通过使用 Wireshark 或 Fiddler 或 WebScarab 等 HTTP 调试代理查看网络流量来确认这一点。

您还可以参阅ServletResponse.setContentType 的 Java EE API 文档以了解此行为:

设置发送给客户端的响应的内容类型,如果响应尚未提交。给定的内容类型可能包括字符编码规范,例如,text/html;字符集=UTF-8。如果在调用 getWriter 之前调用此方法,则仅从给定的内容类型设置响应的字符编码。

可以重复调用此方法来更改内容类型和字符编码。 如果在响应提交后调用此方法无效。

...

【讨论】:

  • application/force-download 是 hack,而不是标准:media-division.com/…
  • @ChristopheRoussy,是的,没有人这样声称。停止在此处发送所有答案。
  • 我想告诉其他 SO 用户它是一个 hack 以及它是如何工作的,因为这在任何地方都没有提到,这里是关于 SO 的解释:stackoverflow.com/questions/10615797/…
【解决方案2】:

在写出文件之前设置内容类型和其他标题。对于小文件,内容被缓冲,浏览器首先获取标题。对于大公司来说,数据是第一位的。

【讨论】:

    【解决方案3】:

    这是一个 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));
    

    据我所知,您做的一切都是正确的。您检查过您的浏览器设置吗?

    【讨论】:

    • 我猜是“你做的一切都是正确的”让你大吃一惊。接受的答案清楚地表明了什么是不正确的。
    • application/force-download 是 hack,而不是标准
    猜你喜欢
    • 2010-12-27
    • 1970-01-01
    • 1970-01-01
    • 2018-05-15
    • 2015-04-16
    • 1970-01-01
    • 2012-02-21
    • 2016-07-15
    • 2017-11-04
    相关资源
    最近更新 更多