我有一个JSF页面,它使用支持bean将PDF文档流式传输到浏览器。这个功能很好用,直到现在我在iOS设备上测试这个功能时还没有遇到任何问题。
在iPad和iPod Touch上的Safari上,PDF流最终只是在获得响应时被粘贴为网页上的不可滚动图层。在桌面上的浏览器中,该文件提示使用Adobe Reader正确保存或打开并打开。这是一个问题,因为只有PDF的第一页的一部分显示在iOS设备上,并且无法查看其他部分。
我已经在网络上对这些设备上的其他PDF进行了测试,但它们的行为并不相同。启动PDF应用程序或Safari加载可滚动预览,这是预期的结果。还有其他人有这个吗?
我的支持bean正在将PDF的缓冲输入流写入输出流。我已设置以下响应标头:
response.setContentType ("application/pdf");
response.setContentLength(inputLength);
response.setHeader ("Content-Disposition", "inline;filename=\"" + saveFilename + ".pdf\"");
response.setHeader ("Cache-Control", "must-revalidate, post-check=0, pre-check=0, public");
我试图将内容处置从内联切换到附件,但这没有帮助。
答案 0 :(得分:0)
我认为这些设备在服务器端需要Range
支持,以便可以在单独的部分中请求内容。这最终可以最终节省不必要的网络带宽,并改善客户端的性能感受。
如果这些PDF是动态生成的,那么最好的办法是将它们写入磁盘文件系统中的临时位置,并将请求重定向到由servlet读取的URL。拥有物理文件是必需的,因为您希望使用RandomAccessFile
以便能够返回文件的部分内容。此类需要磁盘上的物理File
。
这是一个使用File#createTempFile()
创建临时文件并使用文件名作为URL参数将响应重定向到servlet的示例:
File tempFile = File.createTempFile(saveFilename, ".pdf");
OutputStream output = new FileOutputStream(tempFile);
// Now write PDF to output.
// ...
// Then, redirect to some servlet URL.
String tempFilename = tempFile.getName();
externalContext.redirect("/pdf/" + URLEncoder.encode(tempFilename, "UTF-8"));
然后,您需要一个支持范围请求的this one之类的servlet。您只需修改它即可将basePath
值更改为System.getProperty("java.io.tmpdir")
。最后将此servlet映射到/pdf/*
。
或者,如果您对服务器拥有完全的管理控制权,那么您还可以创建一个额外的webapp上下文,指向服务器磁盘文件系统某处的绝对路径。例如。 /var/webapp/pdf
。对于例如Tomcat,您可以通过将以下内容添加到/conf/server.xml
:
<Context docBase="/var/webapp/pdf" path="/pdf" />
这样/var/webapp/pdf
文件夹的内容由http://localhost:8080/context/pdf提供。
在上面的代码示例中稍作更改以指定临时文件位置
File tempFile = File.createTempFile(saveFilename, ".pdf", "/var/webapp/pdf");
// ...
您不再需要自定义servlet了。 Tomcat的DefaultServlet
将负责正确处理Range
个请求。
最后但同样重要的是,考虑将临时文件存储在会话中并实现HttpSessionListener
或HttpSessionAttributeListener
,以便在会话过期时删除临时文件。