Как программно отправить запрос POST на страницу JSF без использования HTML-формы?

У меня очень простой компонент JSF, как показано ниже:

import org.jboss.seam.annotations.Name;

@Name(Sample.NAME)
public class Sample {

    public static final String NAME="df";

    private String text = "text-test";

    public void sampleM(){
        System.out.println("Test: "+text);
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

И форма JSF, связанная с этим компонентом:

<h:form id="sampleForm">
        <h:commandButton id="sampleButton" action="#{df.sampleM()}" value="ok" />
</h:form>

Теперь я хотел бы программно отправить запрос POST в эту форму.

Согласно моему исследованию, ключевыми здесь являются параметры POST. Правильный выбор дает правильные результаты (строка «Test: text-test» печатается на консоли сервера).

Возникает вопрос: Как выбрать правильные данные POST?

Показанная выше форма JSF создает эту HTML-форму:

<form id="sampleForm" name="sampleForm" method="post" action="/pages/main/main.smnet" enctype="application/x-www-form-urlencoded">
    <input type="hidden" name="sampleForm" value="sampleForm" />
    <input id="sampleForm:sampleButton" type="submit" name="sampleForm:sampleButton" value="ok" />
    <input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="j_id65" autocomplete="off" />
</form>

Значит, эти параметры совпадают.

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

Например: когда я отправляю данные POST так же, как в показанной HTML-форме, но с другим значением параметра javax.faces.ViewState, метод компонента не будет выполнен.


person pWoz    schedule 29.08.2012    source источник


Ответы (1)


Я понимаю, что вы в основном спрашиваете, как отправить форму JSF программно, используя какой-либо HTTP-клиент, такой как java.net.URLConnection или Apache HttpComponents Client, верно?

Сначала вам нужно отправить запрос GET и убедиться, что вы поддерживаете один и тот же HTTP-сеанс (в основном, JSESSIONID cookie) для всех запросов. Позвольте вашему HTTP-клиенту извлечь заголовок Set-Cookie из ответа на первый запрос GET, получить из него файл cookie JSESSIONID и отправить его обратно как Cookie заголовок последующих запросов POST. Это будет поддерживать сеанс HTTP на стороне сервера, в противном случае JSF будет рассматривать его как «Просмотр истек», который может возвращать либо в правильно настроенном веб-приложении JSF страницу ошибки HTTP 500 с ViewExpiredException, либо в плохо настроенном веб-приложении JSF. как обновление страницы.

В рамках сохраняющегося состояния JSF и подразумеваемого предотвращения атак CSRF формы должны быть отправлены с допустимым значением javax.faces.ViewState, поскольку клиент получил себя по первоначальному запросу GET. Вам также необходимо убедиться, что вы отправили пару name=value всех других скрытых полей и, в частности, поле кнопки отправки.

Итак, если ваш первоначальный запрос GET возвращает вам этот HTML-код

<form id="sampleForm" name="sampleForm" method="post" action="/pages/main/main.smnet" enctype="application/x-www-form-urlencoded">
    <input type="hidden" name="sampleForm" value="sampleForm" />
    <input id="sampleForm:sampleButton" type="submit" name="sampleForm:sampleButton" value="ok" />
    <input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="j_id65" autocomplete="off" />
</form>

тогда вам нужно его проанализировать (в этом может помочь Jsoup) и извлечь следующие параметры запроса:

  • sampleForm=sampleForm
  • sampleForm:sampleButton=ok
  • javax.faces.ViewState=j_id65

Наконец, отправьте запрос POST на /pages/main/main.smnet именно с этими параметрами запроса (и JSESSIONID cookie!). Однако будьте осторожны, возможно, что (плохой) разработчик JSF пропустил, например id="sampleButton" из <h:commandButton>, а затем JSF автоматически сгенерирует файл, который выглядит в этом формате sampleForm:j_id42. Вы не можете жестко их закодировать, поскольку значение может меняться в зависимости от позиции компонента в дереве на стороне сервера, и тогда вам действительно нужно будет проанализировать полученный HTML.

Тем не менее, разумно связаться с владельцем / администратором сайта и спросить, нет ли API веб-службы, доступного для поставленной вами задачи. Приличный веб-сайт Java EE, который использует приложение JSF для интерфейса HTML, обычно также использует отдельное приложение JAX-RS для интерфейса REST.

Смотрите также:

person BalusC    schedule 29.08.2012
comment
В основном я хотел бы иметь доступ к компонентам JSF и жизненному циклу JSF без использования HTML-форм и HTML-страниц. Является ли это возможным? Предположим, что JSESSIONID известен. Могу ли я как-нибудь запросить у сервера допустимое значение javax.faces.ViewState? Может есть другой способ получить доступ к компонентам JSF? - person pWoz; 29.08.2012
comment
Нет. JSF - это веб-платформа MVC, предназначенная для создания приложений на основе HTML-форм, а не инфраструктура веб-сервисов. Если этот веб-сайт JSF находится под вашим полным контролем, значит, вы в основном используете не тот инструмент для работы. Вместо этого создайте веб-сервис (вы даже можете запускать его одновременно с JSF). API Java EE предлагает для этого API JAX-RS (RESTful) и JAX-WS (SOAP). Если этот веб-сайт JSF не находится под вашим полным контролем, обратитесь к администратору с вопросом, если веб-сервис недоступен. - person BalusC; 29.08.2012
comment
Таким образом, нет возможности создать такой сценарий: у меня есть приложение JSF и несколько веб-сервисов (все на одном сервере в одном приложении). Когда запрос поступает в метод websevice, этот метод использует объект, хранящийся в JSF application scope (нет необходимости запрашивать базу данных)? - person pWoz; 29.08.2012
comment
Объем приложения JSF скрыт под обложками, представленными только атрибутами ServletContext. Если веб-сервис работает в одном и том же веб-приложении и контейнере, он наверняка имеет доступ к одному и тому же экземпляру ServletContext и, следовательно, также ко всем его атрибутам. - person BalusC; 29.08.2012
comment
Пожалуйста, @balusC, можете ли вы ответить на этот вопрос stackoverflow.com/questions/23503948/ - person GingerHead; 07.05.2014
comment
Мы успешно используем JSF в качестве веб-сервиса, передавая сериализованные объекты Java на сервер через параметры HTTP GET и извлекая сериализованный объект ответа в содержимом страницы через компонент outputText. Это даже не это хакерское дело. Мы не использовали JAX WS, потому что он накладывает ограничения на то, как наша база данных должна выглядеть для аутентификации (Realms), и в итоге мы бы зависели от другого механизма JEE (Roles), для изучения которого у нас нет ресурсов. - person Zyl; 18.10.2014