【问题标题】:Spring WS (DefaultWsdl11Definition) HTTP status code with voidSpring WS (DefaultWsdl11Definition) 带有 void 的 HTTP 状态码
【发布时间】:2016-01-20 17:08:01
【问题描述】:

我们有一个基于 Spring WS 和 DefaultWsdl11Definition 的(工作的)SOAP Web 服务。

基本上是这样的:

@Endpoint("name")
public class OurEndpoint {

    @PayloadRoot(namespace = "somenamespace", localPart = "localpart")
    public void onMessage(@RequestPayload SomePojo pojo) {
        // do stuff
    }
}

它是在 Spring 中连接的,它可以正确处理我们所有的 SOAP 请求。唯一的问题是该方法返回 202 Accepted。这不是调用者想要的,他宁愿让我们返回 204 No Content(或者如果这不可能,则返回一个空的 200 OK )。

我们的其他端点有一个有效的响应对象,并返回 200 OK。当 204 可能更合适时,似乎 void 导致 202

是否可以在 Spring WS 中更改响应代码?我们似乎找不到正确的方法来做到这一点。

我们尝试过但没有成功的方法:

  • 将返回类型更改为:
    • HttpStatus.NO_CONTENT
    • org.w3c.dom.Element
  • 添加 @ResponseStatus

有什么想法吗?

【问题讨论】:

  • 202 表示请求已被接受但处理未完成。我想这是由于void 返回类型,DefaultMethodEndpointAdapter 然后没有调用handleMethodReturnValue,因为没有什么可处理的。我想返回 200(或其他)的最简单方法是创建自定义 SoapMessageDispatcher 并重新实现 receive 方法。您可能需要复制整个类(层次结构),因为该类非常封闭(最终方法)。

标签: spring web-services soap spring-ws http-status-codes


【解决方案1】:

与我在 cmets 中所写的不同,创建委托类型的解决方案可能是最简单的。

public class DelegatingMessageDispatcher extends MessageDispatcher {
    private final WebServiceMessageReceiver delegate;

    public DelegatingMessageDispatcher(WebServiceMessageReceiver delegate) {
         this.delegate = delegate;
    }

    public void receive(MessageContext messageContext) throws Exception {
        this.delegate.receive(messageContext);
        if (!messageContext.hasResponse()) {
            TransportContext tc = TransportContextHolder.getTransportContext();
            if (tc != null && tc.getConnection() instanceof HttpServletConnection) {
                ((HttpServletConnection) tc.getConnection()).getHttpServletResponse().setStatus(200);
            }
        }
    }
}

然后你需要配置一个名为messageDispatcher 的bean,它将包装默认的SoapMessageDispatcher

@Bean
public MessageDispatcher messageDispatcher() {
    return new DelegatingMessageDispatcher(soapMessageDispatcher());
}

@Bean
public MessageDispatcher soapMessageDispatcher() {
    return new SoapMessageDispatcher();
}

类似的东西应该可以解决问题。现在,当创建响应时(在返回类型为 void 的情况下),您想要的状态将发送回客户端。

【讨论】:

  • 提供的解决方案不太行,主要原因是HttpServletConnection中的'statusCodeSet'字段为false(即使我们手动设置)。但是你在正确的方向上帮了我很大的忙,我很快就会在这里发布一个工作版本!
【解决方案2】:

在寻找合适的解决方案时,我们遇到了一些丑陋的问题:

  • 创建自定义适配器/拦截器是有问题的,因为当您没有响应时,Spring 不会调用 handleResponse 方法 (void)
  • 手动设置状态码不起作用,因为 HttpServletConnection 保留了一个不会更新的布尔值 statusCodeSet

但幸运的是,我们设法通过以下更改使其工作:

/**
 * If a web service has no response, this handler returns: 204 No Content
 */
public class NoContentInterceptor extends EndpointInterceptorAdapter {

    @Override
    public void afterCompletion(MessageContext messageContext, Object o, Exception e) throws Exception {
        if (!messageContext.hasResponse()) {
            TransportContext tc = TransportContextHolder.getTransportContext();
            if (tc != null && tc.getConnection() instanceof HttpServletConnection) {
                HttpServletConnection connection = ((HttpServletConnection) tc.getConnection());
                // First we force the 'statusCodeSet' boolean to true:
                connection.setFaultCode(null);
                // Next we can set our custom status code:
                connection.getHttpServletResponse().setStatus(204);
            }
        }
    }
}

接下来我们需要注册这个拦截器,这可以使用 Spring 的 XML 轻松完成:

<sws:interceptors>
    <bean class="com.something.NoContentInterceptor"/>
</sws:interceptors>

非常感谢@m-deinum 为我们指明了正确的方向!

【讨论】:

    【解决方案3】:

    重写 afterCompletion 方法确实在完全相同的情况下帮助了我。对于那些使用基于代码的 Spring 配置的人,这里是如何为特定端点添加拦截器的方法。

    用@Component注解自定义拦截器,接下来将自定义拦截器注册到WsConfigurerAdapter,如下所示:

    @EnableWs
    @Configuration
    public class EndpointConfig extends WsConfigurerAdapter {
    
    /**
     * Add our own interceptor for the specified WS endpoint.
     * @param interceptors
     */
    @Override
    public void addInterceptors(List<EndpointInterceptor> interceptors) {
        interceptors.add(new PayloadRootSmartSoapEndpointInterceptor(
                new NoContentInterceptor(),
                "NAMESPACE",
                "LOCAL_PART"
        ));
     }
    }
    

    NAMESPACE 和 LOCAL_PART 应该对应端点。

    【讨论】:

      【解决方案4】:

      如果有人想在返回非无效响应时设置自定义 HTTP 状态,这里是解决方案:

      Spring Boot WS-Server - Custom Http Status

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-22
        • 2013-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-28
        相关资源
        最近更新 更多