如何在不使用 HTML 表单的情况下以编程方式向 JSF 页面发送 POST 请求?

问题描述 投票:0回答:1

我有非常简单的 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参数。 正确选择会给出正确的结果(字符串“测试:文本测试”打印在服务器的控制台上)。

所以问题是:我该如何选择正确的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>

所以这些参数是正确的。

但是我怎样才能找出哪些参数(名称和值)对于任何其他组件来说就足够了?

例如:当我发送与所示 HTML 表单相同但具有不同“javax.faces.ViewState”参数值的 POST 数据时,组件方法将不会被执行。

web-scraping jsf http-post http-request-parameters
1个回答
16
投票

我知道您基本上是在问如何使用某些 HTTP 客户端(例如

java.net.URLConnection
或 Apache HttpComponents 客户端)以编程方式提交 JSF 表单,对吧?

您需要首先发送 GET 请求,并确保在各个请求之间维护相同的 HTTP 会话(基本上是

JSESSIONID
cookie)。让您的 HTTP 客户端从第一个 GET 请求的响应中提取
Set-Cookie
标头,从中获取
JSESSIONID
cookie 并将其作为后续 POST 请求的
Cookie
标头发送回来。这将在服务器端维护 HTTP 会话,否则 JSF 会将其视为“查看已过期”,这可能会在正确配置的 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
cookie!)在
JSESSIONID
上发送 POST 请求。但要小心,(可怜的)JSF 开发人员可能跳过了,例如来自
id="sampleButton"
<h:commandButton>
然后 JSF 会自动生成一个看起来像这种格式
sampleForm:j_id42
的格式。您无法对它们进行硬编码,因为值可能会根据组件在服务器端树中的位置而变化,然后您确实需要将其解析出获得的 HTML。

尽管如此,明智的做法是联系网站所有者/管理员并询问是否没有可用于您想要完成的任务的 Web 服务 API。一个使用 JSF 应用程序作为 HTML 前端的不错的 Java EE 网站通常也会使用一个单独的 JAX-RS 应用程序作为 REST 前端。通过这样的 Web 服务 API 提取信息比抓取 HTML 文档更加容易和可靠。

另请参阅:

© www.soinside.com 2019 - 2024. All rights reserved.