Что именно означает "Ответ уже совершенный"? Как обрабатывать исключения тогда?

Я знаю, что писать бизнес-логику в геттерах и сеттерах - очень плохая практика программирования, но есть ли способ обработать исключения, если ответ уже сделан?

Что именно означает "Ответ уже выполнен" и "Заголовки уже отправлены клиенту"?

Ответы

Ответ 1

Невозможно обработать исключения, если ответ уже сделан. Ответ HTTP существует в основном из заголовка и тела. Заголовки в основном инструктируют клиента (веб-браузер), как именно он должен иметь дело с ответом, например. тип содержимого, длину содержимого, кодировку символов, кодирование тела, инструкции кэша и т.д.

Вы можете видеть заголовки в мониторе HTTP-трафика набора инструментов разработчика webbrowser. Нажмите F12 в Chrome/IE9 +/Firefox23 + и проверьте вкладку "Сеть". Ниже показано, как мой Chrome показывает ваш текущий вопрос:

введите описание изображения здесь

(примечание: вкладка "Ответ" показывает тело ответа)

Тело ответа - это фактическое содержимое, обычно в виде кучи кода HTML. Для записи ответа на сервер обычно требуется буфер фиксированного размера. Размер буфера зависит от версии сервера и конфигурации и обычно составляет 2 КБ ~ 10 КБ. Если этот буфер переполняется, он будет сброшен на другой конец соединения, клиент. Это фиксация ответа. Клиент уже получил первую часть ответа, обычно уже представляющую целую кучу заголовков и, возможно, часть тела.

Конец ответа - это точка без возврата. Сервер не может вернуть уже отправленные байты. Слишком поздно менять заголовки ответов (например, перенаправление в основном инструктируется заголовком Location с новым URL-адресом), не говоря уже о теле ответа. Лучшее, что вы можете сделать, - добавить информацию об ошибке в уже написанный орган ответа. Но это может закончиться каким-то странным выглядящим HTML, поскольку не известно, какие HTML-теги нужно закрыть в этой точке. Браузер не сможет представить его надлежащим образом.

Помимо исключения бизнес-логики в геттерах, чтобы исключения не возникали при рендеринге ответа, другой способ избежать уже зафиксированного ответа состоит в том, чтобы настроить размер буфера ответа как можно большего, чем самая большая страница, которую может обслуживать ваш webapp, Как это сделать, зависит от сервера make/version. Например, в Tomcat вы можете настроить его как атрибут bufferSize элемента <Connector>. Обратите внимание, что это не предотвратит сброс, если ваш собственный код (неявно) вызывает flush() в потоке ответа ответа.

Ответ 2

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

 if ( extContext.isResponseCommitted() ) {
            PartialResponseWriter writer = context.getPartialViewContext().getPartialResponseWriter();
            writer.startElement( "script", null );
            writer.write( "window.location.href = '" + errorPageUrl + "';" );
            writer.endElement( "script" );
            writer.getWrapped().endCDATA();
            writer.endElement( "update" );
            writer.getWrapped().endDocument();
        }
        else {
            extContext.redirect( errorPageUrl );
            context.responseComplete();
        }