В чем разница между перенаправлением и навигацией/переходом и когда использовать что?

В чем разница между навигацией в JSF

FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().getNavigationHandler().handleNavigation(context, null, url);

и перенаправление

HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
response.sendRedirect(url);

и как решить, когда использовать что?

Проблема с навигацией заключается в том, что URL-адрес страницы не изменяется, если в строку запроса URL-адреса навигации не добавлено faces-redirect=true. Однако в моем случае добавление faces-redirect=true вызывает ошибку, если я хочу перенаправить на страницу, отличную от JSF, как обычная HTML-страница.

И еще один вариант: BalusC предложил в ошибке JSF 2.0 для переадресации

Ответ 1

Прежде всего, термин "перенаправление" в мире веб-разработки означает действие отправки клиентом пустого ответа HTTP с помощью только заголовка Location, в котором указан новый URL-адрес, по которому клиент должен отправить новый GET запрос. Итак, в основном:

  • Клиент отправляет HTTP-запрос на somepage.xhtml.
  • Сервер отправляет ответ HTTP с заголовком Location: newpage.xhtml
  • Клиент отправляет HTTP-запрос на newpage.xhtml (это отображается в адресной строке браузера!)
  • Сервер отправляет ответ HTTP с содержимым newpage.xhtml.

Вы можете отслеживать его с помощью набора инструментов разработчика /addon разработчика webbrowser. Нажмите F12 в Chrome/IE9/Firebug и проверьте раздел "Сеть", чтобы увидеть его.

Навигационный манипулятор JSF не отправляет перенаправление. Вместо этого он использует содержимое целевой страницы в качестве ответа HTTP.

  • Клиент отправляет HTTP-запрос на somepage.xhtml.
  • Сервер отправляет ответ HTTP с содержимым newpage.xhtml.

Однако, поскольку исходный HTTP-запрос был somepage.xhtml, URL-адрес в адресной строке браузера не изменился. Если вы знакомы с базовым API сервлета, то вы должны понимать, что это имеет тот же эффект, что и RequestDispatcher#forward().


Что касается того, что вытягивание HttpServletResponse из-под кожухов JSF и вызов sendRedirect() на нем - правильное использование; нет, это не правильное использование. Журналы сервера будут загромождены с помощью IllegalStateException, потому что таким образом вы не сообщаете JSF, что вы уже взяли на себя управление обработкой ответа, и, таким образом, JSF не должен выполнять свое задание по обработке ответов по умолчанию. Фактически вы должны выполнять FacesContext#responseComplete() впоследствии.

Кроме того, каждый раз, когда вам нужно импортировать что-то из пакета javax.servlet.* в артефакт JSF, например управляемый bean, вы должны полностью прекратить писать код и дважды подумать, если вы действительно делаете все правильно и спросите себя если еще нет "стандартного способа JSF" для того, что вы пытаетесь достичь, и/или если задача действительно принадлежит управляемому JSF bean (есть некоторые случаи, когда простой фильтр сервлетов было бы лучше).

Правильный способ выполнения перенаправления в JSF использует строку запроса faces-redirect=true в результате действия:

public String submit() {
    // ...
    return "/newpage.xhtml?faces-redirect=true";
}

Или используя ExternalContext#redirect(), когда вы не находитесь внутри метода действия, такого как метод прослушивания ajax или prerender:

public void listener() throws IOException {
    // ...
    ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
    ec.redirect(ec.getRequestContextPath() + "/newpage.xhtml");
}

(да, вам не нужно класть try-catch вокруг него на IOException, просто разрешите исключение через throws, обработчик сервлета будет обрабатывать его)

Или используя NavigationHandler#handleNavigation() в особых случаях, если вы используете приложения для навигации XML и/или настраиваемый обработчик навигации с помощью встроенного слушателя

public void listener() {
    // ...
    FacesContext fc = FacesContext.getCurrentInstance();
    NavigationHandler nh = fc.getApplication().getNavigationHandler();
    nh.handleNavigation(fc, null, "/newpage.xhtml?faces-redirect=true");
}

Что касается того, почему обработчик навигации не работает для файлов "простого HTML", это просто потому, что обработчик навигации может обрабатывать только представления JSF, а не другие файлы. Тогда вы должны использовать ExternalContext#redirect().

См. также: