处理空的 SOAP 消息

Handling an empty SOAP message

尝试使用 Spring Web 服务处理空的 SOAP 消息但失败。

因此,我请求为某种 PING 方法提供端点。基本上我可以处理的 SOAP 消息如下所示:

<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:def="http://www.something.com/edf/services/defaultservice">
    <soapenv:Header/>
    <soapenv:Body>
        <def:ServiceReqType>
            <transactionId>1111</transactionId>
            <subscriberId>2222</subscriberId>
        </def:ServiceReqType>
    </soapenv:Body>
</soapenv:Envelope>

并且我可以处理正在处理 ServiceReqType.

的端点

但是 PING 看起来像这样:

<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header/>
    <soapenv:Body/>
</soapenv:Envelope>

我无法处理,Spring 记录 Can't handle [SaajSoapMessage]

我需要return的是完全相同的消息。

我知道有一个 type/class 缺失,我会提供给 @PayloadRoot

所以我想知道这个空主体请求的端点规范是什么?

仅供参考,这是我处理 ServiceReqType:

的端点
@PayloadRoot(namespace = NAMESPACE_EDF, localPart = "ServiceReqType")
@ResponsePayload
public ServiceRespType serviceResponse(@RequestPayload ServiceReqType request) {
        LOGGER.debug("-----> ServiceReqType:{}", request);
        return reqProcessor.process(request);
}

更新 1:

所以我尝试通过以下方式实现拦截器:

public class CustomEndpointInterceptor implements EndpointInterceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(CustomEndpointInterceptor.class);

    @Override
    public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
        LOGGER.info("---> Message context: {}", messageContext.toString());
        LOGGER.info("---> Message endpoint: {}", endpoint.toString());
        return false;
    }

    @Override
    public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
        LOGGER.info("handleResponse");
        return false;
    }

    @Override
    public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
        LOGGER.info("handleFault");
        return false;
    }

    @Override
    public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception {
        LOGGER.info("afterCompletion");
    }
}

然后在 WebServiceConfiguration class 我添加了这个:

@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
    interceptors.add(new CustomEndpointInterceptor());
    super.addInterceptors(interceptors);
}

但是还是不行。我得到的是当 SOAP 消息有 BODY 时调用拦截器,但是当它发送 Ping 是 BODYless 时,我再次收到相同的错误消息并且没有调用拦截器。所以看来我必须找到一个更上层的拦截器...

更新 2:

这是此 Ping 的 WSDL 文件的样子...

<message name="PingRequest"/>

<message name="PingResponse"/>

里面没有任何东西......

为了比较,这是 ServiceReqType 的样子:

<message name="ServiceReqType">
  <part name="body" element="tns:ServiceReqTypeDefinition"/>
</message>

然后 ServiceReqTypeDefinition 在随附的 xsd 文件中定义。

更新 3:

所以,找到了拦截​​器无法处理此类消息的原因:-/

以下代码来自 MessageDispatcher 第 234 行。

// No triggering of interceptors if no endpoint is found
if (endpointNotFoundLogger.isWarnEnabled()) {
  endpointNotFoundLogger.warn("No endpoint mapping found for [" + messageContext.getRequest() + "]");
}
throw ex;

所以这是故意的,现在我需要找到如何处理这些不完整或不正确的 SOAP 消息...任何想法,因为重写 Dispatcher 感觉不是正确的方法。

更新 4

因此,我通过扩展 AbstractEndpointMapping class 然后重写 getInternalEndpoint 设法拦截了有效负载,即无效负载,这让我有可能评估消息并查看如果我一直在尝试处理这个空的 Ping 请求。

我认为如果我知道如何定义一个 defaultEndpoint,这一切都会很容易解决,因为我看到万一无法识别 SOAP 消息,因此找不到端点映射,这个 defaultEndpoint用于处理该消息。

我注意到在使用 Beans 的 XML 规范时,有一个 属性 将端点定义为默认端点,但是在使用注释时如何做到这一点?

另一种方法是只创建一个端点,然后 return 它来自 getInternalEndpoint 所以 spring 可以处理处理,我想,但我还不知道如何创建一个端点对象...现在正在处理它。

p.s。 This 文档提到 defaultEndpoint 但没有提到如何以非 XML 定义 Bean 的方式设置它。

所以,最后我不得不创建一个自定义异常处理程序。像这样:

public class CustomEndpointNotFoundException extends Exception {
    public CustomEndpointNotFoundException(String message) {
        super(message);
    }
}

然后:

@Component
@Order(Ordered.LOWEST_PRECEDENCE)
public class NoEndpointFoundEndpointMapping implements EndpointMapping {
    @Override
    public EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception {
        throw new CustomEndpointNotFoundException("");
    }
}

最后:

@Component
public class CustomEndpointExceptionResolver implements EndpointExceptionResolver {
    @Override
    public boolean resolveException(MessageContext messageContext, Object endpoint, Exception ex) {
        if (messageIsPing()) {
            return true;
        }
        return false;
    }
}

所以基本上我把它当作一个错误来处理。这不是真正理想的解决方案恕我直言,我仍然会看看我是否可以拦截端点解析,或者定义一个默认端点。