【问题标题】:Spring WebService - Unable to call service that requires proxy with username and passwordSpring WebService - 无法调用需要具有用户名和密码的代理的服务
【发布时间】:2015-09-11 09:00:14
【问题描述】:

我正在尝试在我的 Java 代码中使用 Spring WebServiceTemplate 来调用供应商提供的受保护的 Web 服务

这是我的 webserviceTemplate 的 spring 配置

    <bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

    <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
        <constructor-arg ref="messageFactory"/>
        <property name="messageSender">
            <bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
                 <property name="httpClient" ref="httpClient"/> 
                <property name="credentials" ref="credentials" />
            </bean>
        </property> 
    </bean>

    <bean id="credentials" class="org.apache.http.auth.UsernamePasswordCredentials">
            <constructor-arg value="${wsdl.username}:${wsdl.password}"/> 
<!--            <constructor-arg index="0" value="${wsdl.username}"/>
            <constructor-arg index="1" value="${wsdl.password}"/> -->
     </bean>

    <bean id="proxy" class="org.apache.http.HttpHost">
        <constructor-arg value="${http.proxy.host}" />
        <constructor-arg value="${http.proxy.port}" />
    </bean> 


<!-- See http://stackoverflow.com/questions/20340470/how-to-spring-ioc-and-httpclient-4-3-1-closeablehttpclient
for configuring the HttpRequestBuilder in spring -->
<bean id="requestConfigBuilder" class="org.apache.http.client.config.RequestConfig" factory-method="custom">
<property name="proxy" ref="proxy" /> 
    <property name="socketTimeout" value="50000" /> 
    <property name="connectTimeout" value="50000" />  
</bean>

<bean id="requestConfig" factory-bean="requestConfigBuilder" factory-method="build" />

<bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
    <property name="defaultRequestConfig" ref="requestConfig" />
</bean>

<bean id="httpClient" factory-bean="httpClientBuilder" factory-method="build" />    

我需要使用代理来访问该服务。网络服务也需要用户名和密码。 我已多次验证代理和凭据详细信息是否有效

调用这个webservice的代码是

public boolean getItems() {

    StringBuilder soapMessage = FileUtil.readFileContent(BASE_CONFIG_LOCATION + GET_ITEMS_XML_TEMPLTE);
    StreamSource source = new StreamSource(new StringReader(soapMessage.toString()));
    StreamResult result = new StreamResult(System.out);

    String endpoint = baseURL + FIND_SERVICE_ENDPOINT;

    boolean webserviceResult = webServiceTemplate.sendSourceAndReceiveToResult(endpoint,source, result);


    return webserviceResult;
}

当我调用此代码时 - 我得到以下异常

 org.springframework.ws.client.WebServiceIOException: I/O error: null; nested exception is org.apache.http.client.ClientProtocolException
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:543)
    at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:492)
    at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:436)
    at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:421)
    at com.test.api.WebServiceImpl.getChecklist(WebServiceImpl.java:69)
    at com.test.api.WebServiceRealCallsTest.testGetChecklist_Success(WebServiceRealCallsTest.java:35)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.apache.http.client.ClientProtocolException
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
    at org.springframework.ws.transport.http.HttpComponentsConnection.onSendAfterWrite(HttpComponentsConnection.java:119)
    at org.springframework.ws.transport.AbstractWebServiceConnection.send(AbstractWebServiceConnection.java:47)
    at org.springframework.ws.client.core.WebServiceTemplate.sendRequest(WebServiceTemplate.java:622)
    at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:585)
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:537)
    ... 35 more
Caused by: org.apache.http.ProtocolException: Content-Length header already present
    at org.apache.http.protocol.RequestContent.process(RequestContent.java:96)
    at org.apache.http.protocol.ImmutableHttpProcessor.process(ImmutableHttpProcessor.java:132)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:182)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    ... 43 more

任何人都可以就我需要做什么来启动和运行这项服务提供任何指导吗?也许我的配置不正确?

谢谢

################ 更新

如果我使用以下代码 - 我的网络服务调用成功返回 但是我宁愿在春天做所有这些,并且不推荐使用 httpClient getParams 方法

    public boolean getItems() {

    HttpComponentsMessageSender sender = (HttpComponentsMessageSender) webServiceTemplate.getMessageSenders()[0];
         sender.getHttpClient().getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
                                    proxy); 

    StringBuilder soapMessage = FileUtil.readFileContent(BASE_CONFIG_LOCATION + GET_ITEMS_XML_TEMPLTE);
    StreamSource source = new StreamSource(new StringReader(soapMessage.toString()));
    StreamResult result = new StreamResult(System.out);

    String endpoint = baseURL + FIND_SERVICE_ENDPOINT;

    boolean webserviceResult = webServiceTemplate.sendSourceAndReceiveToResult(endpoint,source, result);

    return webserviceResult;
}
#### 格林威治标准时间下午 1 点更新

我注意到,如果我在 xml 中为消息发送者指定 httpClient,则使用 org.apache.http.impl.client.InternalHttpClient 类

如果我不指定 httpClient - 使用类 org.apache.http.impl.client.DefaultHttpClient

还有一个有趣的地方,在 org.springframework.ws.transport.http.HttpComponentsMessageSender 类中

/**
 * Create a new instance of the {@code HttpClientMessageSender} with a default {@link HttpClient} that uses a
 * default {@link org.apache.http.impl.conn.PoolingClientConnectionManager}.
 */
public HttpComponentsMessageSender() {
    org.apache.http.impl.client.DefaultHttpClient defaultClient =
            new org.apache.http.impl.client.DefaultHttpClient(new org.apache.http.impl.conn.PoolingClientConnectionManager());
    defaultClient.addRequestInterceptor(new RemoveSoapHeadersInterceptor(), 0);

    this.httpClient = defaultClient;
    setConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT_MILLISECONDS);
    setReadTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS);
}

/**
 * Create a new instance of the {@code HttpClientMessageSender} with the given
 * {@link HttpClient} instance.
 * <p>
 * This constructor does not change the given {@code HttpClient} in any way. As such,
 * it does not set timeouts, nor does it
 * {@linkplain org.apache.http.impl.client.DefaultHttpClient#addRequestInterceptor(org.apache.http.HttpRequestInterceptor) add}
 * the {@link RemoveSoapHeadersInterceptor}.
 *
 * @param httpClient the HttpClient instance to use for this sender
 */
public HttpComponentsMessageSender(HttpClient httpClient) {
    Assert.notNull(httpClient, "httpClient must not be null");
    this.httpClient = httpClient;
}

如您所见 - 对于 DefaultClient - 它调用一个方法来删除soapHeaders,但不是为 HttpClient。我查看了这个方法并考虑添加一个拦截器来完成相同的工作,但是 HttpRequest 在任何拦截器方法上都不可用

有什么想法可以从这里开始吗?

【问题讨论】:

  • 我认为它与授权标头有关。请结帐stackoverflow.com/questions/13494148/…
  • 好吧,这是个好建议。我正在尝试通过 Eclipse TCP/IP 拦截器运行我的请求,但没有任何乐趣,因为端点是 https
  • 直接在浏览器上查看怎么样?

标签: java spring web-services spring-mvc proxy


【解决方案1】:

以防其他人遇到这种情况。诀窍是将拦截器添加到自定义客户端。

CloseableHttpClient httpClient = HttpClients.custom()
    .setSSLHostnameVerifier(new NoopHostnameVerifier())
    .setSSLContext(ContextUtil.getTrustAllCertsContext())
    .addInterceptorFirst(new HttpComponentsMessageSender.RemoveSoapHeadersInterceptor())
    .build();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    • 2016-01-02
    • 2010-11-13
    相关资源
    最近更新 更多