Servlet 生成 PDF,但有时调用行为会陷入困境
在首先生成的 iframe 内生成预览页面后,servlet 生成 PDF 文档。这通常是这样工作的:
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if ("directPrintDocumentDoIt".equals(request.getParameter("method"))) {
generatePDF(request, response);
}
if ("directPrintDocumentWaiting".equals(request.getParameter("method"))) {
String queryString = request.getQueryString().replace("directPrintDocumentWaiting", "directPrintDocumentDoIt");
renderWaiting(request, response, queryString);
}
if ("directPrintDocument".equals(request.getParameter("method"))) {
String queryString = request.getQueryString().replace("directPrintDocument", "directPrintDocumentWaiting");
renderIFrameWaiting(request, response, queryString);
}
}
首先,“directPrintDocument”和方法“renderIFrameWaiting”被调用,它生成 iframe 页面并将内容写入 servlet 响应(iframe src 调用 doPost 的下一部分。我确信这不会产生任何错误,因此我省略了此代码片段)。然后调用“directPrintDocumentWaiting”和“renderWaiting”方法,在先前生成的 iframe 页面中生成预览页面,同时生成的 javascript 调用“directPrintDocumentDoIt”,最终生成 PDF:
private void renderWaiting(HttpServletRequest request, HttpServletResponse response, String queryString) throws IOException {
StringBuffer output = new StringBuffer();
response.setContentType("text/html; charset=ISO-8859-1");
response.setHeader("Cache-Control", "no-cache");
output.append("<html>\n");
output.append("<head>\n");
output.append("<meta http-equiv='Content-Type' content='text/html;charset=iso-8859-1'>\n");
output.append("<meta http-equiv='expires' content='0'>\n");
output.append("<meta http-equiv='cache-control' content='no-cache'>\n");
output.append("<meta http-equiv='pragma' content='no-cache'>\n");
output.append("</head>\n");
output.append("<script type=\"text/javascript\">\n");
output.append("function formSubmit() {\n");
output.append("document.forms[0].target=\'_self\';\n");
output.append("document.body.style.cursor = \"wait\";\n");
output.append("var formAction = document.forms[0].action;\n");
output.append("document.forms[0].submit();\n");
output.append("}\n");
output.append("</script>\n");
output.append("<body onload=\"self.focus(); formSubmit();\">\n");
output.append("<form name=\"druckenForm\" method=\"post\" action=\"" + request.getRequestURI() + "?" + queryString + "\" onsubmit=\"return false;\">\n");
output.append("<p align=\"center\" valign=\"center\">Druck wird erzeugt...\n</p>\n");
output.append("<p align=\"center\" valign=\"center\">Der erstmalige Start kann etwas länger dauern.</p>\n");
output.append("</form>\n");
output.append("</body>\n");
output.append("</html>");
response.setContentLength(output.length());
response.getOutputStream().write(output.toString().getBytes());
response.getOutputStream().flush();
response.getOutputStream().close();
}
这通常有效,但有时会发生奇怪的情况。不知怎的,看起来最后一个调用“directPrintDocumentDoIt”将被调用两次,因此generatePDF也将被调用两次,整个打印输出会陷入困境(在大多数情况下,PDF将被白页覆盖)。这种情况发生的概率为 50 次之一,因此几乎无法重现。首先,我想到了一些线程问题,所以我在每次调用时记录了线程ID:
log.info("> current thread:" + Thread.currentThread().getId());
线程ID总是相同的,所以我怀疑这确实是一个线程问题。令我困惑的是,当发生此错误时,fiddler 会在执行 javascript POST 调用后记录第四次调用。通常有 3 个调用(“directPrintDocument”、“directPrintDocumentWaiting”和“directPrintDocumentDoIt”)。当有 4 次调用时,它总是以相同的方式发生:“directPrintDocumentDoIt”将被调用两次(与 POST 请求相同的 URL),但突然作为 GET 请求调用。我不知道这个 GET 请求来自哪里(在“generatePDF”中没有其他请求调用)。因此,要么 javascript 产生一些奇怪的行为(但为什么很少),要么 Web 容器(Websphere)产生一些我不明白的奇怪的事情。有趣的是,fiddler 在第三次和第四次调用时显示不同的实体大小。正确的 POST 调用的实体大小为 84.138 字节。第四次调用(错误的一次)有 83.883 字节。我不知道这意味着什么,但也许这些信息很有帮助。我感觉在我重新启动或发布到 Websphere 后,此错误更频繁地发生。在这种情况下,它会在第一次尝试时发生(但并非总是如此)。这不可能是巧合。有什么想法吗?
A servlet generates a PDF document after a preview page has been generated within an iframe which is generated at first. This usually works and looks like this:
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if ("directPrintDocumentDoIt".equals(request.getParameter("method"))) {
generatePDF(request, response);
}
if ("directPrintDocumentWaiting".equals(request.getParameter("method"))) {
String queryString = request.getQueryString().replace("directPrintDocumentWaiting", "directPrintDocumentDoIt");
renderWaiting(request, response, queryString);
}
if ("directPrintDocument".equals(request.getParameter("method"))) {
String queryString = request.getQueryString().replace("directPrintDocument", "directPrintDocumentWaiting");
renderIFrameWaiting(request, response, queryString);
}
}
First of all "directPrintDocument" and the method "renderIFrameWaiting" is invoked which generates the iframe page and writes the content to the servlet response (The iframe src invokes the next part of doPost. I'm sure this produces no errors so I omit this code fragment). Then "directPrintDocumentWaiting" and the method "renderWaiting" is invoked which generates a preview page within the previous generated iframe page while the generated javascript invokes "directPrintDocumentDoIt" which finally generates the PDF:
private void renderWaiting(HttpServletRequest request, HttpServletResponse response, String queryString) throws IOException {
StringBuffer output = new StringBuffer();
response.setContentType("text/html; charset=ISO-8859-1");
response.setHeader("Cache-Control", "no-cache");
output.append("<html>\n");
output.append("<head>\n");
output.append("<meta http-equiv='Content-Type' content='text/html;charset=iso-8859-1'>\n");
output.append("<meta http-equiv='expires' content='0'>\n");
output.append("<meta http-equiv='cache-control' content='no-cache'>\n");
output.append("<meta http-equiv='pragma' content='no-cache'>\n");
output.append("</head>\n");
output.append("<script type=\"text/javascript\">\n");
output.append("function formSubmit() {\n");
output.append("document.forms[0].target=\'_self\';\n");
output.append("document.body.style.cursor = \"wait\";\n");
output.append("var formAction = document.forms[0].action;\n");
output.append("document.forms[0].submit();\n");
output.append("}\n");
output.append("</script>\n");
output.append("<body onload=\"self.focus(); formSubmit();\">\n");
output.append("<form name=\"druckenForm\" method=\"post\" action=\"" + request.getRequestURI() + "?" + queryString + "\" onsubmit=\"return false;\">\n");
output.append("<p align=\"center\" valign=\"center\">Druck wird erzeugt...\n</p>\n");
output.append("<p align=\"center\" valign=\"center\">Der erstmalige Start kann etwas länger dauern.</p>\n");
output.append("</form>\n");
output.append("</body>\n");
output.append("</html>");
response.setContentLength(output.length());
response.getOutputStream().write(output.toString().getBytes());
response.getOutputStream().flush();
response.getOutputStream().close();
}
This usually works but sometimes something strange happens. Somehow it looks like that the last invocation "directPrintDocumentDoIt" will be invoked twice so generatePDF will be invoked twice too and the whole printout gets bogged down (in the most cases the PDF will be overridden by a white page). This happens by a chance of 1 of 50 times, so it's hardly ever reproducable. First of all I thought of some thread issues so I logged the thread id at every invocation:
log.info("> current thread:" + Thread.currentThread().getId());
The thread id is always the same, so I doubt it's really a thread problem. What perplexes me is the fact that when this error occures fiddler records a 4th invocation after the javascript POST invocation has been executed. Usually there are 3 invocations ("directPrintDocument", "directPrintDocumentWaiting" and "directPrintDocumentDoIt"). When there are 4 invocations it always happens in the same manner: "directPrintDocumentDoIt" will be invoked twice (same URL with the POST request) but suddendly as a GET request. I have no clue where this GET request comes from (In "generatePDF" are no other request invocations). So either the javascript produces some strange behaviour (but why then very seldom) or the web container (Websphere) makes some strange things I don't understand. The interesting thing is that fiddler shows different entity sizes at the 3rd and 4th invocation. The POST invocation which is the right one has an entity size of 84.138 bytes. The 4th invocation (the wrong one) has 83.883 bytes. I don't know what this means but maybe this information is helpful. I have the feeling that this errors happens more often after I restarted or published to Websphere. In this case it happens at the first try (but not always). This cannot be coincidence. Any ideas what's going on here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
显然该错误是由 pdfwriter 引起的。容易出错的代码如下所示:
我不知道为什么,但有时这个标头无论如何都会导致第二个请求。当我将其更改为以下内容时,生成 pdf 后不再出现白页。所以这似乎是解决方案。
Obviously the error was caused by the pdfwriter. The errorprone code looked like this:
I don't know why, but sometimes this header causes anyhow a 2nd request. When I change it to the following, I get no white pages anymore after pdf generation. So this seems to be the solution.