Java 在 Internet Explorer 中使用 ServletOutputStream 通过 HTTPS 从 Servlet 返回 CSV 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/899858/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Returning CSV file from Servlet using ServletOutputStream over HTTPS in Internet Explorer
提问by Brian
I have a Servlet which is returning a csv file that is 'working' over HTTP in both internet explorer and firefox. When I execute the same Servlet over HTTPS only firefox continues to download the csv file over HTTPS. I don't think this is necessarily an Internet 6 or 7 issue described on MSDN:
我有一个 Servlet,它返回一个 csv 文件,该文件在 Internet Explorer 和 firefox 中都通过 HTTP“工作”。当我通过 HTTPS 执行相同的 Servlet 时,只有 firefox 继续通过 HTTPS 下载 csv 文件。我认为这不一定是MSDN上描述的 Internet 6 或 7 问题:
The message is:
消息是:
Internet Explorer cannot download data.csv from mydomain.com Internet Explorer was not able to open this Internet site. The requested site is either unavailable or cannot be found. Please try again later.
Internet Explorer 无法从 mydomain.com 下载 data.csv Internet Explorer 无法打开此 Internet 站点。请求的站点不可用或找不到。请稍后再试。
Please note that the site is still 'up' after this message and you can continue to browse the site, its just the download of the CSV that prompts this message. I have been able to access similar files over https on IE from other j2ee applications so I believe it is our code. Should we not be closing the bufferedOutputStream?
请注意,此消息后该站点仍处于“启动”状态,您可以继续浏览该站点,只需下载提示此消息的 CSV 文件即可。我已经能够从其他 j2ee 应用程序通过 IE 上的 https 访问类似的文件,所以我相信这是我们的代码。 我们不应该关闭 bufferedOutputStream 吗?
UPDATE
更新
whether to close or not to close the output stream:I asked this question on the java posse forums and the discussionthere is also insightful. In the end it seems that no container should rely on the 'client' (your servlet code in this case) to close this output stream. So if your failure to close the stream in your servlet causes a problem it is more a reflection on the poor implementation of your servlet container than your code. I sited the behavior of the IDEs and tutortials from Sun, Oracle and BEA and how they are also inconsistent in whether they close the stream or not.
是否关闭输出流:我在 java posse 论坛上问过这个问题,那里的讨论也很有见地。最后,似乎没有容器应该依赖“客户端”(在这种情况下是您的 servlet 代码)来关闭此输出流。因此,如果您未能关闭 servlet 中的流导致问题,那么这更多地反映了 servlet 容器的糟糕实现,而不是您的代码。我找到了来自 Sun、Oracle 和 BEA 的 IDE 和教程的行为,以及它们在是否关闭流方面也不一致。
About IE specific behavior: In our case a separate product 'Oracle Web Cache' was introducing the additional header values which impacts Internet explorer only because of the way IE implements the 'No Cache' requirement (see the MSDN article). The code is:
关于 IE 的特定行为:在我们的案例中,一个单独的产品“Oracle Web 缓存”引入了影响 Internet Explorer 的附加标头值,这仅仅是因为 IE 实现“无缓存”要求的方式(请参阅 MSDN 文章)。代码是:
public class DownloadServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
ServletOutputStream out = null;
ByteArrayInputStream byteArrayInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
response.setContentType("text/csv");
String disposition = "attachment; fileName=data.csv";
response.setHeader("Content-Disposition", disposition);
out = response.getOutputStream();
byte[] blobData = dao.getCSV();
//setup the input as the blob to write out to the client
byteArrayInputStream = new ByteArrayInputStream(blobData);
bufferedOutputStream = new BufferedOutputStream(out);
int length = blobData.length;
response.setContentLength(length);
//byte[] buff = new byte[length];
byte[] buff = new byte[(1024 * 1024) * 2];
//now lets shove the data down
int bytesRead;
// Simple read/write loop.
while (-1 !=
(bytesRead = byteArrayInputStream.read(buff, 0, buff.length))) {
bufferedOutputStream.write(buff, 0, bytesRead);
}
out.flush();
out.close();
} catch (Exception e) {
System.err.println(e); throw e;
} finally {
if (out != null)
out.close();
if (byteArrayInputStream != null) {
byteArrayInputStream.close();
}
if (bufferedOutputStream != null) {
bufferedOutputStream.close();
}
}
}
回答by Arne Burmeister
I am really confused about your "from back through the breast into the head" write mechanism. Why not simple (the servlet output stream will be bufferend, thats container stuff):
我真的很困惑你的“从后面穿过乳房到头部”的书写机制。为什么不简单(servlet 输出流将是 bufferend,那是容器的东西):
byte[] csv = dao.getCSV();
response.setContentType("text/csv");
response.setHeader("Content-Disposition", "attachment; filename=data.csv"));
reponse.setContentLength(csv.length);
ServletOutputStream out = response.getOutputStream();
out.write(csv);
There should also be no need to flush the output stream nor to close.
也不需要刷新输出流或关闭。
The header content should not be parsed case sensitive by IE, but who knows: do not camelcase fileName
. The next question is the encoding. CSV is text, so you should use getWriter(
) instead or getOutputStream()
and set the content type to "text/csv; charset=UTF-8" for example. But the dao
should provide the CSV as String instead of byte[].
IE 不应该解析标题内容区分大小写,但谁知道:不要使用驼峰命名法fileName
。下一个问题是编码。CSV 是文本,因此您应该使用getWriter(
) 或 getOutputStream()
并将内容类型设置为“text/csv; charset=UTF-8”。但是dao
应该提供 CSV 作为字符串而不是字节 []。
The servlet code has nothing to d with HTTPS, so the protocol does not matter from the server side. You may test the servlet from localhost with HTTP i hope.
servlet 代码与 HTTPS 没有任何关系,因此从服务器端看协议无关紧要。我希望您可以使用 HTTP 测试来自 localhost 的 servlet。
What about filters in your application? A filter may als set an HTTP header (or as footer) with cache-control for example.
您的应用程序中的过滤器呢?例如,过滤器还可以使用缓存控制设置 HTTP 标头(或作为页脚)。