【问题标题】:Returning CSV file from Servlet using ServletOutputStream over HTTPS in Internet Explorer在 Internet Explorer 中通过 HTTPS 使用 ServletOutputStream 从 Servlet 返回 CSV 文件
【发布时间】:2009-05-22 20:32:13
【问题描述】:

我有一个 Servlet,它返回一个 csv 文件,该文件在 Internet Explorer 和 Firefox 中都通过 HTTP “工作”。当我通过 HTTPS 执行相同的 Servlet 时,只有 firefox 继续通过 HTTPS 下载 csv 文件。我认为这不一定是on MSDN 描述的 Internet 6 或 7 问题:

消息是:

Internet Explorer 无法下载 来自 mydomain.com 互联网的 data.csv 资源管理器无法打开此 互联网网站。请求的站点是 要么不可用,要么找不到。 请稍后再试。

请注意,在收到此消息后,该站点仍处于“启动”状态,您可以继续浏览该站点,只是下载了提示此消息的 CSV。我已经能够通过 IE 上的 https 从其他 j2ee 应用程序访问类似的文件,所以我相信这是我们的代码。 我们不应该关闭 bufferedOutputStream 吗?

更新

是否关闭输出流: 我在 java posse 论坛上问了这个问题,discussion 也很有见地。最后,似乎没有容器应该依赖“客户端”(在这种情况下是您的 servlet 代码)来关闭此输出流。因此,如果您未能关闭 servlet 中的流导致出现问题,则它更多地反映了 servlet 容器的不良实现而不是您的代码。我定位了来自 Sun、Oracle 和 BEA 的 IDE 和教程的行为,以及它们在是否关闭流方面也不一致。

关于 IE 特定行为:在我们的案例中,一个单独的产品“Oracle Web 缓存”引入了额外的标头值,这仅因为 IE 实现“无缓存”要求的方式而影响 Internet Explorer( see the MSDN article)。 代码是:

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

【问题讨论】:

  • Firefox 有效。你能描述一下IE会发生什么吗?你没有得到任何东西,它是否挂起,文件是否被截断,...?
  • MSDN 文章突出显示了该消息。我会尽快用消息更新问题。

标签: java servlets jakarta-ee


【解决方案1】:

我真的对你的“从背部到胸部到头部”的写入机制感到困惑。为什么不简单(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);

也应该不需要刷新输出流或关闭。

标题内容不应该被IE解析大小写,但谁知道:不要驼峰fileName。下一个问题是编码。 CSV 是文本,因此您应该使用 getWriter() 或 getOutputStream() 并将内容类型设置为“text/csv; charset=UTF-8”。但是dao 应该提供 CSV 作为字符串而不是字节 []。

servlet 代码与 HTTPS 无关,因此从服务器端看,协议无关紧要。我希望您可以使用 HTTP 从 localhost 测试 servlet。

您的应用程序中的过滤器怎么样?例如,过滤器也可以设置带有缓存控制的 HTTP 标头(或作为页脚)。

【讨论】:

  • 它在大多数浏览器中都可以在 HTTP 和 HTTPS 中工作,但带有 HTTPS 的 Internet Explorer 除外(我链接到的 MSDN 文章中指出了相同的消息)。我在您的示例中注意到您没有执行 out.close()。我正在寻找确认 Servlet 也不应该调用 out.close()。
  • 我同意缓冲 IO 的东西是不必要的。不要那样做。同样,我认为没有必要关闭流。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-29
  • 2012-03-14
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 2018-05-04
相关资源
最近更新 更多