一尘不染

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

java

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

阅读 1069

收藏
2020-03-24

共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之前调用此方法,则仅根据给定的内容类型设置响应的字符编码。

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

2020-03-24