我试图将多个PDF文件下载为一个zip文件,然后更新JSF页面上的详细信息—有效地显示我正在处理这些文件。我在后台使用两个请求实现了这一点- 1)更新DB详细信息并刷新屏幕2)下载zip文件。
这在单工作站windows环境中工作得很好,但是当我在Linux环境中部署它时,在负载平衡器后面,我在尝试下载zip时得到一个空白页面。我已经编写了SOP统计数据来打印通过JSF BB发送到ServletOutputStream的文件的大小,并且我发现正在打印正确的文件大小。但是不知何故,我不断丢失zip和更新的JSF。这种情况在Windows中也会随机发生,这让我很担心。请提供宝贵的建议,帮助我解决这个问题。
你可以考虑以下几点:我使用的是Richfaces 3.3.3 Final, IE 8浏览器,响应传输编码类型是分块的。
= = = =BB方法如下所示:
String checkoutDoc = service.checkout(docId,true,contract, error);
FacesContext ctx = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) ctx.getExternalContext().getResponse();
File tempPdf = new File(checkoutDoc);URI tempURI = tempPdf.toURI();
URL pdfURL = tempURI.toURL();ServletOutputStream outstream =response.getOutputStream();
try
{
URLConnection urlConn = pdfURL.openConnection();
response.setContentType("application/zip");
response.setHeader("Transfer-Encoding", "chunked");
response.addHeader("Content-disposition", "attachment;filename="+docId.toString()+".zip" );
BufferedInputStream bufInStrm = new BufferedInputStream (urlConn.getInputStream());
int readBytes = 0;
int bufferSize = 8192;
byte[] buffer = new byte[bufferSize];
while ((readBytes = bufInStrm.read(buffer)) != -1){
if (readBytes == bufferSize) {
outstream.write(buffer);
}else{
outstream.write(buffer, 0, readBytes);
}
outstream.flush();
response.flushBuffer();
}
bufInStrm.close();
}finally{
outstream.close();
}
FacesContext.getCurrentInstance().responseComplete();
}
我使用Firefox Http监视器捕获的响应头如下所示。
(Request-Line) POST /XXX/application/pages/xxx.xhtml HTTP/1.1
Host xxx.xxx.com
User-Agent Mozilla/5.0 (Windows NT 5.1; rv:5.0.1) Gecko/20100101 Firefox/5.0.1
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip, deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection keep-alive
Referer http://xxx.com/xxx/application/pages/xxx.xhtml
Cookie JSESSIONID=E27C156AA37E5984073FAB847E4958D2.XXXX; fontSize=null; pageWidth=fullWidth
Content-Type multipart/form-data; boundary=---------------------------288695814700
Content-Length 1442
你应该不设置自己的Transfer-Encoding: chunked
头,如果你是实际上不写用块编码自己使用例如ChunkedOutputStream
的文件。当响应缓冲区已满且响应内容长度未知时,Servlet API将自动执行此操作。但是,如果您自己设置了这个头,而没有实际地以分块编码写出正文,则行为是完全未指定的,并且依赖于所使用的servlet容器。
删除头文件,让Servlet API完成它的工作。为了提高性能(以便Servlet API在响应缓冲区已满时不会切换到分块编码),也可以设置响应内容长度头。
话虽如此,你的流式传输方法有点笨拙。不需要将File
按摩到URL
, for
回路中的if-else
也不需要。我可以给您以下建议吗?
// ...
File tempPdf = new File(checkoutDoc);
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.setResponseContentType("application/zip");
externalContext.setResponseHeader("Content-Disposition", "attachment;filename="" + docId + ".zip"");
externalContext.setResponseHeader("Content-Length", String.valueOf(tempPdf.length()));
Files.copy(tempPdf.toPath(), externalContext.getResponseOutputStream());
FacesContext.getCurrentInstance().responseComplete();
参见:
- 如何从JSF支持bean提供文件下载?