Сервлет генерирует PDF, но иногда поведение вызова застревает - PullRequest
0 голосов
/ 19 сентября 2011

Сервлет генерирует документ PDF после того, как страница предварительного просмотра была сгенерирована в iframe, который генерируется сначала. Обычно это работает и выглядит так:

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 и записывает содержимое в ответ сервлета (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&auml;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 будет переопределен белой страницей). Это случается с вероятностью 1 из 50 раз, поэтому вряд ли когда-либо будет воспроизводимым. Прежде всего, я подумал о некоторых проблемах с потоками, поэтому регистрировал идентификатор потока при каждом вызове:

log.info("> current thread:" + Thread.currentThread().getId());

Идентификатор потока всегда одинаков, поэтому я сомневаюсь, что это действительно проблема потока. Меня сбивает с толку тот факт, что когда эта ошибка происходит, Fiddler записывает 4-й вызов после выполнения вызова POST javascript. Обычно существует 3 вызова («directPrintDocument», «directPrintDocumentWaiting» и «directPrintDocumentDoIt»). Когда есть 4 вызова, это всегда происходит одинаково: «directPrintDocumentDoIt» будет вызываться дважды (один и тот же URL-адрес с запросом POST), но внезапно, как запрос GET. Я понятия не имею, откуда приходит этот запрос GET (в "generatePDF" нет других вызовов запроса). Так что либо javascript выдает какое-то странное поведение (но почему то очень редко), либо веб-контейнер (Websphere) создает странные вещи, которые я не понимаю. Интересно, что Fiddler показывает разные размеры сущностей при 3-м и 4-м вызовах. Правильный вызов POST имеет размер объекта 84,138 байт. 4-й вызов (неправильный) имеет 83,883 байта. Я не знаю, что это значит, но, возможно, эта информация полезна. У меня такое ощущение, что эти ошибки происходят чаще после перезапуска или публикации в Websphere. В этом случае это происходит с первой попытки (но не всегда). Это не может быть совпадением. Есть идеи, что здесь происходит?

1 Ответ

0 голосов
/ 22 сентября 2011

Очевидно, что ошибка была вызвана pdfwriter. Код errorprone выглядел так:

        response.reset();
        response.setContentType("application/pdf");
        response.setContentLength(pdfContent.length);
        response.setHeader("Content-Disposition", "inline; filename=RANDOMFILE.pdf");
        response.addHeader("Accept-Ranges", "bytes");
        response.getOutputStream().write(pdfContent);
        response.getOutputStream().flush();
        response.getOutputStream().close(); 

Я не знаю почему, но иногда этот заголовок так или иначе вызывает второй запрос. Когда я изменяю это на следующее, я не получаю больше белых страниц после генерации PDF. Так что, похоже, это решение.

response.setContentType("application/pdf");
response.setContentLength(pdfContent.length);
response.getOutputStream().write(pdfContent);
response.getOutputStream().flush();
response.getOutputStream().close(); 
...