如何强制浏览器下载文件?

2022-08-31 17:36:33

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

答案 1

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

因此,您的方法应按如下方式编写(这不会编译,因为它仅仅是一种表示):

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 容器不知道哪些标头(在 HTTP 响应中出现在正文之前),那么它可能会设置适当的标头来确保响应有效;因此,在写入文件后设置标头是徒劳和多余的,因为容器可能已经设置了标头。您可以通过使用Wireshark或HTTP调试代理(如Fiddler或WebScarab)查看网络流量来确认这一点。

您也可以参考 ServletResponse.setContentType 的 Java EE API 文档来了解此行为:

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

可以反复调用此方法以更改内容类型和字符编码。如果在提交响应后调用此方法,则此方法不起作用。

...


答案 2

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


推荐