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

How to programmatically send POST request to JSF page without using HTML form?

提问人:pWoz 提问时间:8/29/2012 最后编辑:BalusCpWoz 更新时间:11/10/2023 访问量:25037

问:

我有非常简单的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 请求发送到此表单。

根据我的调查,这里的关键是开机自检参数。 正确选择会给出正确的结果(字符串“Test:text-test”打印在 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>

所以这些参数是相关的。

但是,我怎样才能知道哪些参数(名称和值)足以满足任何其他组件的需求呢?

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

Web 抓取 JSF HTTP-POST HTTP-REQUEST-PARAMETERS

评论


答:

16赞 BalusC 8/29/2012 #1

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

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

作为 JSF 的有状态特性和隐含的 CSRF 攻击防护的一部分,当客户端在初始 GET 请求中检索到自身时,必须使用有效值提交表单。您还需要确保发送所有其他隐藏字段的对,尤其是提交按钮之一。javax.faces.ViewStatename=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 请求,其中包含这些请求参数(和 cookie!不过要小心,一个(可怜的)JSF 开发人员可能已经跳过了,例如 然后 JSF 将自动生成一个看起来像这种格式的 。您不能对它们进行硬编码,因为该值可能会根据组件在服务器端树中的位置而变化,然后您确实需要将其解析为获取的 HTML。/pages/main/main.smnetJSESSIONIDid="sampleButton"<h:commandButton>sampleForm:j_id42

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

另请参阅:

评论

0赞 pWoz 8/29/2012
基本上,我希望在不使用 HTML 表单和 HTML 页面的情况下访问 JSF 组件和 JSF 生命周期。可能吗?让我们假设是已知的。我可以以某种方式向服务器询问有效值吗?也许还有另一种方法可以访问 JSF 组件?JSESSIONIDjavax.faces.ViewState
0赞 BalusC 8/29/2012
不。JSF 是一个基于 Web 的 MVC 框架,旨在生成基于 HTML 表单的应用程序,它不是一个 Web 服务框架。如果该 JSF 网站在您的完全控制之下,那么您基本上使用了错误的工具来完成这项工作。而是创建一个 Web 服务(您甚至可以与 JSF 并行运行它)。Java EE API 为此提供了 JAX-RS (RESTful) 和 JAX-WS (SOAP) API。如果该 JSF 网站不在您的完全控制之下,那么如果没有可用的 Web 服务,请联系管理员进行查询。
0赞 pWoz 8/29/2012
所以没有办法生成这样的场景:我有一个 JSF 应用程序和几个 Web 服务(都在一个应用程序的同一服务器上)。当请求到达websevice方法时,该方法使用存储在JSF中的对象(无需查询数据库)?application scope
1赞 BalusC 8/29/2012
JSF 应用程序范围只是由 的属性表示。如果 Web 服务在同一个 Web 应用和容器中运行,它肯定可以访问同一个实例,因此也可以访问它的所有属性。ServletContextServletContext
0赞 GingerHead 5/7/2014
请@balusC,你能 stackoverflow.com/questions/23503948/ 回答这个问题吗?