无法使用 Apache CXF 客户端从 WS 服务接收回消息:读取超时

Could not receive message back from WS service using Apache CXF Client: Read time out

我正在尝试调用基于 IIS WPF 的 Web 服务,其 WSDL 具有以下策略:

<wsp:Policy wsu:Id="custom_policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
        <wsp:Policy>
          <sp:TransportToken>
            <wsp:Policy>
              <sp:HttpsToken RequireClientCertificate="false"/>
            </wsp:Policy>
          </sp:TransportToken>
          <sp:AlgorithmSuite>
            <wsp:Policy>
              <sp:Basic256/>
            </wsp:Policy>
          </sp:AlgorithmSuite>
          <sp:Layout>
            <wsp:Policy>
              <sp:Strict/>
            </wsp:Policy>
          </sp:Layout>
          <sp:IncludeTimestamp/>
        </wsp:Policy>
      </sp:TransportBinding>
      <sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
        <wsp:Policy>
          <sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
            <wsp:Policy>
              <sp:WssUsernameToken10/>
            </wsp:Policy>
          </sp:UsernameToken>
        </wsp:Policy>
      </sp:SignedSupportingTokens>
      <sp:Wss11 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
        <wsp:Policy/>
      </sp:Wss11>
      <sp:Trust10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
        <wsp:Policy>
          <sp:MustSupportIssuedTokens/>
          <sp:RequireClientEntropy/>
          <sp:RequireServerEntropy/>
        </wsp:Policy>
      </sp:Trust10>
      <wsaw:UsingAddressing/>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

使用 Apache CXF 客户端和以下代码:

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(ITerytWs1.class);
factory.setAddress("https://uslugaterytws1test.stat.gov.pl/terytws1.svc");
ITerytWs1 info = (ITerytWs1) factory.create();
Map ctx = ((BindingProvider)info).getRequestContext();
ctx.put("ws-security.username", "TestPubliczny");
ctx.put("ws-security.password", "1234abcd");
ctx.put("ws-security.callback-handler", ClientPasswordCallback.class.getName());
var zal = info.isLoggedIn();

依赖项是:

compile group: 'org.apache.cxf', name: 'cxf-rt-frontend-jaxws', version: '3.3.7'
compile group: 'org.apache.cxf', name: 'cxf-rt-transports-http', version: '3.3.7'
compile group: 'com.sun.activation', name: 'javax.activation', version: '1.2.0'
compile group: 'org.apache.cxf', name: 'cxf-rt-ws-security', version: '3.3.7'
compile group: 'com.sun.xml.messaging.saaj', name: 'saaj-impl', version: '1.5.2'

我只收到读取超时:

lip 16, 2020 1:58:31 PM org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
WARNING: Interceptor for {http://tempuri.org/}ITerytWs1Service#{http://tempuri.org/}CiekawostkiSIMC has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Could not receive Message.
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:65)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:530)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:441)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:356)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:314)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
  [...]
Caused by: java.net.SocketTimeoutException: SocketTimeoutException invoking https://uslugaterytws1test.stat.gov.pl/terytws1.svc: Read timed out
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    [..]
Caused by: java.net.SocketTimeoutException: Read timed out
    at java.base/java.net.SocketInputStream.socketRead0(Native Method)
    [...]
Could not receive Message.
javax.xml.ws.WebServiceException: Could not receive Message.
    at org.apache.cxf.jaxws.JaxWsClientProxy.mapException(JaxWsClientProxy.java:183)

[...] 原因:java.net.SocketTimeoutException:调用 SocketTimeoutException https://uslugaterytws1test.stat.gov.pl/terytws1.svc:读取超时 在 java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(本机方法) [...]

这个WS policy怎么配置正确,是客户端的问题还是其他的?

我必须使用 SoapUI 检查发送给服务的信封类型以获得正确答案,然后我必须对代码执行相同的操作。之前的问题是错误的请求被发送到服务器并且服务器得到内部异常(可能)并且没有返回错误请求的答案。

这是我对class所做的:

import lombok.Getter;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.ws.addressing.WSAddressingFeature;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
import org.tempuri.ITerytWs1;

import javax.inject.Inject;
import java.util.HashMap;
import java.util.Map;

public class WebServiceClient {

@Getter
private ITerytWs1 service;
private final ApiClientConfiguration apiClientConfiguration;
private final ClientPasswordCallback clientPasswordCallback;

@Inject
public WebServiceClient(ApiClientConfiguration apiClientConfiguration) {
    this.apiClientConfiguration = apiClientConfiguration;
    this.clientPasswordCallback = new ClientPasswordCallback(apiClientConfiguration);
    initializeService();
    configureService();
}

private void configureService() {
    var client = ClientProxy.getClient(service);
    var endpoint = client.getEndpoint();
    Map<String, Object> outInterceptorProperties = createOutInterceptorProperties();
    var wssOutInterceptor = new WSS4JOutInterceptor(outInterceptorProperties);
    endpoint.getOutInterceptors().add(wssOutInterceptor);
}

private void initializeService() {
    var factory = new JaxWsProxyFactoryBean();
    var wsAddressingFeature = new WSAddressingFeature();
    factory.getFeatures().add(wsAddressingFeature);
    factory.setServiceClass(ITerytWs1.class);
    factory.setAddress(apiClientConfiguration.getAddress());
    service = (ITerytWs1) factory.create();
}

private Map<String, Object> createOutInterceptorProperties() {
    Map<String,Object> outInterceptorProperties = new HashMap<>();
    outInterceptorProperties.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
    outInterceptorProperties.put(WSHandlerConstants.USER, apiClientConfiguration.getUsername());
    outInterceptorProperties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
    outInterceptorProperties.put(WSHandlerConstants.ADD_USERNAMETOKEN_NONCE, "true");
    outInterceptorProperties.put(WSHandlerConstants.ADD_USERNAMETOKEN_CREATED, "true");
    outInterceptorProperties.put(WSHandlerConstants.MUST_UNDERSTAND, "false");
    // Callback used to retrieve password for given user.
    outInterceptorProperties.put(WSHandlerConstants.PW_CALLBACK_REF, clientPasswordCallback);
    return outInterceptorProperties;
}
}