如何以编程方式将POST请求发送到JSF页面而不使用HTML表单?

时间:2012-08-29 10:21:51

标签: jsf jsf-2 http-post http-request-parameters

我有非常简单的JSF bean,如下所示:

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参数。 正确选择会给出正确的结果(字符串'测试:文本测试'打印在serwer的控制台上)。

所以问题是:我应该如何选择正确的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'参数值,将不会执行组件方法。

1 个答案:

答案 0 :(得分:11)

我知道您基本上是在询问如何使用某些HTTP客户端(例如java.net.URLConnection或Apache HttpComponents Client)以编程方式提交JSF表单,对吗?

您需要先发送GET请求,并确保跨请求维护相同的HTTP会话(基本上是JSESSIONID cookie)。让您的HTTP客户端从第一个GET请求的响应中提取Set-Cookie标头,从中获取JSESSIONID cookie并将其作为后续POST请求的Cookie标头发回。这将维护服务器端的HTTP会话,否则JSF会将其视为“View Expired”,它可能会返回一个配置正确的JSF Web应用程序,一个带有ViewExpiredException的HTTP 500错误页面,或者配置错误JSF Web应用程序表现为页面刷新。

作为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

最后在/pages/main/main.smnet上发送一个POST请求,其中包含那些请求参数(以及JSESSIONID cookie!)。但要小心,(可怜的)JSF开发人员可能会跳过例如来自id="sampleButton"的{​​{1}}然后JSF会自动生成一个看起来像这种格式<h:commandButton>的版本。您无法对它们进行硬编码,因为值可能会根据组件在服务器端树中的位置而发生变化,然后您真的需要将其解析出所获得的HTML。

尽管如此,与网站所有者/管理员联系并询问是否没有可用于您所考虑的任务的Web服务API是明智之举。一个体面的Java EE网站,它使用一个用于HTML前端的JSF应用程序,通常也会为REST前端使用单独的JAX-RS应用程序。

另见: