2016-02-24 4 views
5

Я работаю с веб-каркасом (uPortal), который обрабатывает ошибки, просто бросая исключение и затем вися. Рамки работают путем рендеринга XML в HTML. Когда возникает исключение, браузер получает отображаемый контент до элемента XML-шаблона, который терпит неудачу, а затем браузер просто сидит и ждет тайм-аута. Теория нашей команды заключается в том, что контент отправляется до возникновения ошибки, что меня удивило. Другие рамки, с которыми я работал, похоже, заканчивают рендеринг перед отправкой содержимого.Переадресовать веб-страницу после отправки некоторого содержимого

Мой вопрос: есть ли способ перенаправить браузер после того, как контент уже отправлен? В этом случае мы находимся в середине рендеринга содержимого тега <script>, но ошибка может произойти потенциально в любом месте html.

Мое единственное, что я хочу сказать, это вставить некоторый javascript вверху страницы и попытаться изменить поведение структуры, чтобы быстро выйти из строя и закрыть соединение и добавить теги </body> и </html> при возникновении ошибки. Затем вышеупомянутый javascript будет запускаться на pageload и обнаруживать, есть ли содержимое всей страницы и направить клиентскую сторону, если нет. Возможно, он может искать специальный скрытый div внизу страницы.

Существуют ли какие-либо примеры решений, решающих эту проблему по-разному, или людей, использующих аналогичные рамки, которые работают вокруг этой проблемы?

ответ

0

Я не знаю, что рамки, но

В HTTP, каждый ответ имеет ответ-код, связанный с ним. Поскольку страница уже частично передана/отображена, код статуса (обычно «200») уже был отправлен (и получен).

У браузера не существует способа принять другой код ответа (например, «301» для перенаправления) для того же ответа! Также сервер не может отправить другой код ответа, потому что исходный код ответа уже был отправлен и отправлен клиенту.

Ваше описание ошибки и знаний о http-протоколе подразумевает, что, вероятно, существует некоторая ошибка реализации в используемых компонентах framework/server, или это было сделано намеренно, рискуя ситуацией, в которой вы находитесь сейчас ...

0

Чтобы перенаправить страницу, вам необходимо установить информацию о переадресации в заголовке. но вы можете написать заголовок, как только вы начнете писать контент (может быть заголовок уже получен клиентом к тому времени, вы соревнуетесь писать весь документ)

Но, вы можете сделать это по-другому, как показано ниже

1.let document loading complete and record if you need to redirect the page while rendering 
2. add a unique request-id identifier for each page load 
3. invoke ajax call with request-id (may be rest call) to server asking if page needs to be redirected. 
4. if page needs to be redirected , do so, via javascript in browser at client end. 
0

Ответ HTTP состоит из заголовков и необязательного содержимого ответа. После того, как вы начали писать ответ на соединение сокета, вы не можете его вернуть. В вашем примере: если вы столкнулись с ошибкой в ​​середине создания контента, вы не можете добавить заголовок перенаправления - секция заголовка уже записана.

Вышеприведенное утверждение не совсем верно: в HTTP chunked transfer encoding ответ отправляется отдельными кусками. Последний фрагмент может иметь необязательный трейлер, содержащий поля заголовка объекта и теоретически заголовок перенаправления. Но если вы можете использовать этот механизм, это другой вопрос. Например, контейнер сервлета может использовать кодировку с кодировкой, но не дает вам API для установки трейлера.

Но запись не должна начинаться сразу: например, HttpServletResponse поддерживает буфер для содержимого ответа. Если вы устанавливаете заголовки и начинаете писать контент, заполняется только буфер, и вы все равно можете сбросить ответ и начать все заново. Но как только буфер переполняется, ответ записывается в соединение, а HttpServletResponse теперь совершил.

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

Второй способ избежать ошибок во время создания контента - просто убедиться, что они не могут произойти. Сначала соберите все ваши данные, необходимые для ответа (например, совершив небезопасные вызовы базы данных), затем на втором этапе создайте ответ - второй этап теперь должен не сбой (за исключением случаев, когда у вас есть ошибки в коде).

Вы уже упоминали о третьем способе устранения ошибки, поскольку клиент дезинфицирует ответ и предпринимает некоторые действия, связанные с обнаружением ошибок (например, путем включения сценария в сгенерированный ответ HTML).

+0

Как другие решения решить эту проблему? Например, как Весна? Ожидается ли весна до тех пор, пока не будут отображены представления перед записью ответа? Или все рамки имеют эту проблему? – xdhmoore

+0

@xdhmoore в конце Весна также основана на технологии сервлетов, и насколько я знаю, следуя второй стратегии, упомянутой в моем ответе. Этот https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc может представлять интерес, но в основном это касается того, как отправлять на значимую страницу ошибок, а не как избежать или восстановить из исключения. – wero

+0

Подходит ли весна для исключения исключений из слоя view/jsp? Там, где я запутался, в этой структуре мы наблюдаем, как страница замораживается в исключении после загрузки всего предыдущего содержимого.Я думал, что другие фреймворки, такие как spring, все сделали перед тем, как начать возвращать контент (чтобы они могли вернуть страницу ошибки в случае исключения), но эта структура, похоже, начинает возвращать контент до того, как будет сделана рендеринг, которая, как мне кажется, ваш вариант 3 выше единственного выбора ... – xdhmoore

1

Вы должны либо зафиксировать ошибку, либо захватить вывод в буфере. Если вы можете обработать исключение, вероятно, можно напечатать простой тег сценария как

<script> window.location.href = 'some_new_url';</script> 

Если браузер понимает доктайп быть что-то связанное с HTML, он будет выполнять этот тег.

Если вы можете захватить вывод в буфере, когда вы обрабатываете ошибку, вы можете решить перенаправить HTTP-браузер в браузер и уничтожить выходной буфер до этой точки.

Что касается других фреймов, на PHP вы можете просто включить буферизацию вывода с помощью ob_start(), которая не начнет отправлять контент до тех пор, пока запрос не будет полностью завершен.

0

Единственный надежный способ сделать это - создать прокси-сервер HttpServletResponse объект, который кэширует ответ. Вам нужно будет дать uPortal этот прокси вместо фактического HttpServletResponse и отправлять только результат с использованием реального ответа после завершения обработки/отправки перенаправления, если обработка завершилась неудачно.

Это ограничение на использование протокола HTTP, которое вы не можете отправить перенаправление HTTP после запуска выхода.

Другие возможные способы зависят от переадресации HTML или Javascript, но поскольку вы пишете, что ошибка может произойти в любой момент, было бы трудно распечатать ее таким образом, чтобы браузеры достоверно интерпретировали ее как перенаправление.

Смежные вопросы