【问题标题】:Streaming a pdf through a servlet to a browser通过 servlet 将 pdf 流式传输到浏览器
【发布时间】:2011-04-21 15:34:37
【问题描述】:

我有一个典型的 servlet,可以将 pdf 流式传输到浏览器。 pdf 存储在我的 servlet 从中获取的内部服务器上。如果我直接从浏览器中点击 servlet,则会显示 pdf。如果我在网页中的 <IMG> 标记中尝试相同的 URL,... 损坏的管道。

关于为什么会这样的任何见解?

作为一项实验,我可以毫无问题地流式传输 gif。

这是我几乎从内部网络中清除的代码:

public class PdfServlet extends HttpServlet {

    private static final Logger log = Logger.getLogger(PdfServlet.class.getName());

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res) {

        String url = (String) req.getParameter("url");

        log.info("The URL is " + url);
        String format = "application/pdf";
//           String format = "image/gif";

        streamBinaryData(url, format, res);

    }

    /*
     * This Method Handles streaming Binary data
     * <p>
     * @param String urlstr ex: http;//localhost/test.pdf etc.
     * @param String format ex: pdf or audio_wav or msdocuments etc.
     * @param ServletOutputStream outstr
     * @param HttpServletResponse resp
     */
    private void streamBinaryData(
            String urlstr,
            String format,
            HttpServletResponse resp) {

        ServletOutputStream outstr = null;
        String ErrorStr = null;

        try {
            outstr = resp.getOutputStream();

            //find the right MIME type and set it as contenttype
            resp.setContentType(format);
            BufferedInputStream bis = null;
            BufferedOutputStream bos = null;
            try {
                URL url = new URL(urlstr);
                URLConnection urlc = url.openConnection();
                int length = urlc.getContentLength();

                resp.setContentLength(length);
//                resp.setHeader("Content-Length", String.valueOf(+length));
//                resp.setHeader("Content-Disposition", "inline");

                // Use Buffered Stream for reading/writing.
                InputStream in = urlc.getInputStream();
                bis = new BufferedInputStream(in);
                bos = new BufferedOutputStream(outstr);
                byte[] buff = new byte[length];
                int bytesRead;
                // Simple read/write loop.
                while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                    log.info("Got a chunk of " + bytesRead);
                    bos.write(buff, 0, bytesRead);
                }
            } catch (Exception e) {
                e.printStackTrace();
                ErrorStr = "Error Streaming the Data";
                outstr.print(ErrorStr);
            } finally {
                log.info("finally!!!");
                if (bis != null) {
                    bis.close();
                }
                if (bos != null) {
                    bos.close();
                }
                if (outstr != null) {
                    outstr.flush();
                    outstr.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

...和 ​​HTML 文件。 pdf 因管道损坏而失败,即使内容类型返回为“application/pdf”,也会显示 gif 图像。

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Cheesy Servlet Experiment</title>
    </head>
    <body>
        <h1>Cheesy Servlet Experiment</h1>

        <P>
            <img src="http://10.0.0.9/ServletExperiment/pdf?url=http%3a%2f%2fwww.samplepdf.com%2fsample.pdf" alt="yah mon">
        <P>
            <img src="http://10.0.0.9/ServletExperiment/pdf?url=http%3a%2f%2fbbs.homeshopmachinist.net%2fimages%2fstatusicon%2fforum_new.gif" alt="yah mon">
    </body>
</html>

编辑 - 以下在 FF 中有效。我不知道它有多标准。

<object data="http://www.samplepdf.com/sample.pdf" type="application/pdf" width="600" height="600">
    alt : <a href="http://www.samplepdf.com/sample.pdf">test.pdf</a>
</object>

Interesting info here。看起来支持得很好。

【问题讨论】:

  • 在帖子中使用可能的解决方案进行编辑。
  • 功能需求是什么?显示 PDF 内联? &lt;object&gt;&lt;iframe&gt; 是解决此问题的常规方法。
  • 在这一点上,我认为要求是 something 工作,哈哈。带有 PDF 的服务器位于我们的防火墙后面。测试时,测试人员显然仍在 VPN 上或有一个缓存页面。我们不知道。但是我们的客户都看不到他们的 PDF,而且事情很……紧张。我们在星期六推了一把。

标签: java pdf servlets stream


【解决方案1】:

第一件事:您正试图立即阅读length。 这不是一个好的做法,因为它不能保证你完成任务

尝试读取较小的块 byte [] read_buffer = new byte[1024 * 10] 这样你一次可以读取 10kb。

然后在bos 上写下这 10kb。

保持这个循环,直到你通过read 函数得到-1

是的。你不应该对 pdf 使用 img 标签

【讨论】:

    【解决方案2】:

    问题是您试图显示带有img 标签的PDF 文档。 img 只能处理简单的图像格式,如 JPEG、GIF 或 PNG。

    通常普通浏览器无法自行显示 PDF 内容。如果没有安装 PDF 查看器插件,则浏览器只会显示一个保存对话框来下载 PDF 文件。

    因此,最安全的方法是您的 HTML 页面仅包含指向您的 PDF 文件的链接。也许用target="_blank" 打开一个新的浏览器窗口。

    【讨论】:

      【解决方案3】:

      您应该使用锚标记(如果您必须使用 img,请使用 A 包裹 IMG,IMG 的 src 指向真实图像)。锚的 href 将是您显示 PDF 的服务器。让您在 servlet 中设置正确的内容类型。

      【讨论】:

        【解决方案4】:

        您的浏览器甚至可以在img 元素中显示PDF 文件吗?这真的不太可能。我认为浏览器在发现它实际上不是图像时会终止连接。

        有些浏览器不会抱怨内容类型。他们检查图像文件并自行确定图像的格式。这可以解释为什么显示您的 GIF 图片。

        【讨论】:

        • 我从来没有想过。
        猜你喜欢
        • 2013-04-18
        • 2011-04-13
        • 2013-04-18
        • 2013-05-26
        • 1970-01-01
        • 2010-09-14
        • 2023-04-04
        • 2015-04-21
        • 2013-12-19
        相关资源
        最近更新 更多