Java Web应用程序:添加Content-Disposition头以强制浏览器“另存为”行为

7
即使它不是HTTP 1.1 / RFC2616的一部分,希望在浏览器中强制将资源“下载”(而不是显示)的Web应用程序可以像这样使用Content-Disposition头:
Content-Disposition: attachment; filename=FILENAME

虽然它只在RFC2183中定义,而不是HTTP 1.1的一部分,但它在大多数web浏览器中按预期工作。

因此从客户端来看,一切都足够好。

然而,在服务器端,在我的情况下,我有一个Java webapp,我不知道该如何设置该标头,特别是在以下情况下...

我将在Amazon S3实例上托管一个文件(例如称为“bigfile”),我的S3存储桶可以使用部分地址访问,例如:files.mycompany.com/,所以用户将能够通过files.mycompany.com/bigfile访问此文件。

现在是否有一种方法可以编写一个servlet(或一个.jsp),以便当用户想要下载该文件时始终添加Content-Disposition标头?

代码会是什么样子,还有什么需要注意的地方吗?


所以,如果文件将从S3下载,并且将向S3服务器发出HTTP请求,那么S3必须添加此标头,而不是您的应用程序,对吗? - Igor Artamonov
@splix:看到了你的评论,我猜是这样...但是弄清楚这个问题恰恰就是我的问题所在 :) 如果您能详细解释一下,我会点赞并接受答案 :) - SyntaxT3rr0r
@splix:看到了你的评论,我在谷歌上搜索了一下S3,发现由于广大用户的要求,你可以将文件以“自定义标头”的方式上传到你的存储桶中,这将是解决我的问题的好方法! - SyntaxT3rr0r
1
实际上,看起来亚马逊管理界面可以让您直接设置标题,如果这对您有用的话。感谢您提出这个问题! - Pointy
Content-Disposition是HTTP的一部分;它在IANA头字段注册表(http://www.iana.org/assignments/message-headers/perm-headers.html)中被定义为HTTP头字段,当前的定义在RFC 6266中。 - Julian Reschke
显示剩余2条评论
4个回答

4
我照 Pointy 指出的方法实现了这个功能。现在不再直接链接到资源(在我的情况下是 pdf 文件),而是链接到一个名为 download.jsp 的 JSP 文件,该文件会解析 GET 参数并将 PDF 作为下载提供。
点击此处下载。
以下是我使用的 JSP 代码,在 IE8、Chrome 和 Firefox 中都能正常工作:
<%@page session="false"
            contentType="text/html; charset=utf-8"
            import="java.io.IOException,
                    java.io.InputStream,
        java.io.OutputStream,
        javax.servlet.ServletContext,
        javax.servlet.http.HttpServlet,
        javax.servlet.http.HttpServletRequest,
        javax.servlet.http.HttpServletResponse,
        java.io.File,
        java.io.FileInputStream"
 %>
<%  
//Set the headers.
response.setContentType("application/x-download"); 
response.setHeader("Content-Disposition", "attachment; filename=downloaded.pdf");

[pull the file path from the request parameters]   

File file = new File("[pdf path pulled from the requests parameters]");
FileInputStream fileIn = new FileInputStream(file);
ServletOutputStream outstream = response.getOutputStream();

byte[] outputByte = new byte[40096];

while(fileIn.read(outputByte, 0, 40096) != -1)
{
    outstream.write(outputByte, 0, 40096);
}
fileIn.close();
outstream.flush();
outstream.close();

%>

2
您不会有一个直接引用文件的URL。相反,您将拥有一个指向您的servlet代码(或指向服务器端框架中某种操作代码)的URL。这反过来需要访问文件内容并将其传输到客户端,在设置标题后。 (您还需要记住根据需要处理缓存控制标头。)
HttpServletResponse类具有API,可让您设置所需的所有标头。您必须确保在开始转储文件内容之前设置标头,因为标头实际上必须首先出现在发送到浏览器的流中。
这与您可能具有动态生成下载的servlet的情况并没有太大区别。
编辑:我将在此处保留上面的内容以便后人参考,但我要注意,当您存储文件时,可能有一些方法可以将一些HTTP标头交给S3,以便亚马逊在提供文件时将它们返回。我不确定您应该如何做到这一点,也不确定“Content-disposition”是否是可以通过这种方式设置的标头,但我会继续寻找。

@Pointy:所以我理解它与我在问题中提到的S3案例不兼容,对吗?我的意思是,如果我必须通过服务器流传文件,那岂不是违背了使用S3的初衷吗? - SyntaxT3rr0r
是的,我同意,但请看我的评论 - 我承认在涉及S3细节方面我是个轻量级的人,但是我正在寻找... - Pointy

0
我刚通过谷歌找到这个。
我也有类似的问题,但我仍然想使用Servlet(因为我生成内容)。

然而,在Servlet中,以下这行代码就是你所需要的全部。

response.setHeader("Content-Disposition", "attachment; filename=downloadedData.json");

0
在根目录下放置一个名为.htaccess的文件,并添加以下行:
Header set Content-Disposition attachment

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接