使用 REST 插件对 Struts2 的 POST 请求未收到响应

POST request to Struts2 with REST plugin not receiving response

我有一个使用 struts2-rest-plugin v.2.2.3 的 struts2 应用程序。

在将请求路由到操作及其方法方面,一切都很好,我还使用 ModelDriven 来指定在使用 JSON 和 XML 等扩展时要序列化的对象。

我遇到的问题是,当我向 struts 层发送 POST 或 PUT 请求时,我得到一个空响应。

我正在向操作发送一个 POST 请求,如下所示:http://localhost:8080/alert-settings!update.json。我在该方法中有一个断点,它被调用并且代码运行并完成。我有一种感觉,问题可能是我正在尝试使用 ModelDriven 接口向我发送响应,并且由于某种原因,rest-plugin 不喜欢这样,但我不知道它为什么会这样。

在使用 REST 插件时接收来自 POST 请求的响应是否存在已知问题?我到处找,真的找不到任何关于它的东西。

感谢任何帮助,我可以根据要求提供更多详细信息。


我遇到了同样的问题。您是否尝试在 struts.xml 文件中设置:

1
struts.rest.content.restrictToGET = false

查看其余插件文档中的最后一个设置


我实际上发现这是其余插件中的一行导致此:

1
2
3
4
// don't return any content for PUT, DELETE, and POST where there are no errors
if (!hasErrors && !"get".equalsIgnoreCase(ServletActionContext.getRequest().getMethod())) {
  target = null;
}

这是在 selectTarget() 方法中的 org.apache.struts2.rest.RestActionInvocation 中。我觉得这很烦人,因为它并没有真正遵循 REST 架构,就像在某些情况下能够为 POST、DELETE 和 PUT 请求返回响应对象的选项一样。

我通过扩展 RestActionProxyFactoryRestActionInvocation 并在我的 struts xml 中指定使用它来解决这个问题,如下所示:

1
2
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="restOverride" class="uk.co.ratedpeople.tp.rest.RPRestActionProxyFactory" />
<constant name="struts.actionProxyFactory" value="restOverride" />

这允许我在 POST 请求中返回对象时始终使用 struts 插件。

RestActionProxyFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class RPRestActionProxyFactory extends RestActionProxyFactory {

    @Override
    public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext) {
        if (namespace.startsWith(this.namespace)) {
            ActionInvocation inv = new RPRestActionInvocation(extraContext, true);
            container.inject(inv);
            return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
        } else {
            return super.createActionProxy(namespace, actionName, methodName, extraContext, executeResult, cleanupContext);
        }
    }

}

RestActionInvocation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class RPRestActionInvocation extends RestActionInvocation {

    public RPRestActionInvocation(Map extraContext, boolean pushAction) {
        super(extraContext, pushAction);
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void selectTarget() {

        // Select target (content to return)
        Throwable e = (Throwable)stack.findValue("exception");
        if (e != null) {

            // Exception
            target = e;
            hasErrors = true;

        } else if (action instanceof ValidationAware && ((ValidationAware)action).hasErrors()) {

            // Error messages
            ValidationAware validationAwareAction = ((ValidationAware)action);

            Map errors = new HashMap();
            if (validationAwareAction.getActionErrors().size() > 0) {
                errors.put("actionErrors", validationAwareAction.getActionErrors());
            }
            if (validationAwareAction.getFieldErrors().size() > 0) {
                errors.put("fieldErrors", validationAwareAction.getFieldErrors());
            }
            target = errors;
            hasErrors = true;

        } else if (action instanceof ModelDriven) {

            // Model
            target = ((ModelDriven)action).getModel();

        } else {
            target = action;
        }

        // don't return any content for PUT, DELETE, and POST where there are no errors
//      if (!hasErrors && !"get".equalsIgnoreCase(ServletActionContext.getRequest().getMethod())) {
//          target = null;
//      }
    }

}


我过去使用过具有混合结果类型的 struts 操作,例如返回 json、xml 和图块。我不确定这是否是推荐的方法,但即使使用了约定,它也需要使用 struts.xml 进行一些配置。也许您已经这样做了,但不确定提供的信息不足。

Struts.xml 设置:

1
2
3
4
5
6
7
8
9
10
<constant name="struts.convention.default.parent.package" value="restful"/>

<package name="restful"  extends="rest-default, struts-default, json-default">
    <result-types>
        <result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult" />
        <result-type name="json" class="com.googlecode.jsonplugin.JSONResult"/>
    </result-types>

    ....
</package>

我已经设置了额外的结果类型,以便稍后用于特定操作。在动作类中,您可以通过动作或方法设置结果类型。

动作类:

1
2
3
4
5
6
7
8
@Results({
    @Result(name ="JsonSuccess", type ="json"),
    @Result(name ="success", type ="tiles", location ="/tickets.tiles")
})

public class EventController extends RestActionSupport implements ModelDriven<EventBean>{
     ...
}

关于 json 结果的其他注意事项,我注意到当我有一个可序列化的对象作为结果返回时,如果该对象包含其他复杂对象以及返回嵌入对象的 getter/setter,我经常会收到空结果或无结果。我经常最终编写 json package器对象以用于我的 json 结果,其中 getter/setter 只返回 java 类型(String、int、Boolean 等)而不是嵌入式对象。我认为已经使用委托 getter/setter 解决了这个问题,但我必须回去看看一些旧代码。