Java webapp:添加内容处置标头以强制浏览器“另存为”行为

发布于 2024-08-24 07:43:19 字数 676 浏览 8 评论 0原文

即使它不是 HTTP 1.1/RFC2616 的一部分,希望强制在浏览器中下载资源(而不是显示)的网络应用程序也可以使用 Content-Disposition 标头,例如这个:

Content-Disposition: attachment; filename=FILENAME

尽管它只在 RFC2183 中定义,而不是 HTTP 1.1 的一部分,但它可以按照需要在大多数 Web 浏览器中工作。

所以从客户端来看,一切都足够好了。

然而,在服务器端,就我而言,我有一个 Java Web 应用程序,我不知道应该如何设置该标头,特别是在以下情况下......

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

现在有没有一种方法可以制作 servlet (或 .jsp),以便在用户需要时始终添加 Content-Disposition 标头下载该文件?

代码是什么样子的?有什么陷阱(如果有的话)?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

酷炫老祖宗 2024-08-31 07:43:19

正如 Pointy 指出的那样,我得到了这个工作。现在不是直接链接到资产(在我的例子中是 pdf),而是链接到名为 download.jsp 的 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();

%>

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();

%>
り繁华旳梦境 2024-08-31 07:43:19

您不会有直接引用该文件的 URL。相反,您将拥有一个指向 servlet 代码(或服务器端框架中某种操作代码)的 URL。反过来,在设置标头后,必须访问文件内容并将它们铲到客户端。 (您还需要记住根据需要处理缓存控制标头。)

HttpServletResponse 类具有可让您设置所需的所有标头的 API。您必须确保在开始转储文件内容之前设置标头,因为标头实际上必须在发送到浏览器的流中排在第一位。

这与您可能有一个可以即时生成下载的 servlet 的情况没有太大区别。

编辑为了后代,我将把这些内容留在这里,但我会注意到,当您存储<时,有(或可能有)某种方法可以将一些 HTTP 标头移交给 S3 /em> 一个文件,这样亚马逊会在文件送出时将其吐出。我不太确定你会如何做到这一点,我也不确定“Content-disposition”是一个可以这样设置的标头,但我会继续寻找。

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.

披肩女神 2024-08-31 07:43:19

.htaccess 文件放入根文件夹中,其中包含以下行:

Header set Content-Disposition attachment

Put a .htaccess file in the root folder with the following line:

Header set Content-Disposition attachment
赠我空喜 2024-08-31 07:43:19

我刚刚通过谷歌找到了这个。

我遇到了类似的问题,但我仍然想使用 Servlet(当我生成内容时)。


然而,在 Servlet 中,以下行就足够了。

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

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");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文