Java webapp: adding a content-disposition header to force browsers "save as" behavior
Even though it's not part of HTTP 1.1/RFC2616 webapps that wish to force a resource to be downloaded (rather than displayed) in a browser can use the Content-Disposition
header like this:
Content-Disposition: attachment; filename=FILENAME
Even tough it's only defined in RFC2183 and not part of HTTP 1.1 it works in most web browsers as wanted.
So from the client side, everything开发者_运维知识库 is good enough.
However on the server-side, in my case, I've got a Java webapp and I don't know how I'm supposed to set that header, especially in the following case...
I'll have a file (say called "bigfile") hosted on an Amazon S3 instance (my S3 bucket shall be accessible using a partial address like: files.mycompany.com/) so users will be able to access this file at files.mycompany.com/bigfile.
Now is there a way to craft a servlet (or a .jsp) so that the Content-Disposition
header is always added when the user wants to download that file?
What would the code look like and what are the gotchas, if any?
I got this working as Pointy pointed out. Instead of linking directly to the asset - in my case pdfs - one now links to a JSP called download.jsp which takes and parses GET parameters and then serves out the pdf as a download.
Download here
Here's the jsp code I used. Its working in IE8, Chrome and 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();
%>
You wouldn't have a URL that was a direct reference to the file. Instead, you'd have a URL that leads to your servlet code (or to some sort of action code in your server-side framework). That, in turn, would have to access the file contents and shovel them out to the client, after setting up the header. (You'd also want to remember to deal with cache control headers, as appropriate.)
The HttpServletResponse class has APIs that'll let you set all the headers you want. You have to make sure that you set up the headers before you start dumping out the file contents, because the headers literally have to come first in the stream being sent out to the browser.
This is not that much different from a situation where you might have a servlet that would generate a download on-the-fly.
edit I'll leave that stuff above here for posterity's sake, but I'll note that there is (or might be) some way to hand over some HTTP headers to S3 when you store a file, such that Amazon will spit those back out when the file is served out. I'm not exactly sure how you'd do that, and I'm not sure that "Content-disposition" is a header that you can set up that way, but I'll keep looking.
Put a .htaccess
file in the root folder with the following line:
Header set Content-Disposition attachment
I just found this via google.
And I had a simmilar problem, but I still want to use a Servlet (as I generate the Content).
However the following line is all you need in a Servlet.
response.setHeader("Content-Disposition", "attachment; filename=downloadedData.json");
精彩评论