Java 使用SpringWS客户端动态设置自定义HTTP头

Java 使用SpringWS客户端动态设置自定义HTTP头,java,spring,http,header,spring-ws,Java,Spring,Http,Header,Spring Ws,使用SpringWS时,如何在客户端动态设置自定义HTTP头(而不是SOAP头) public class AddHttpHeaderInterceptor implements ClientInterceptor { public boolean handleFault(MessageContext messageContext) throws WebServiceClientException { return true; } public boolean han

使用SpringWS时,如何在客户端动态设置自定义HTTP头(而不是SOAP头)

public class AddHttpHeaderInterceptor implements ClientInterceptor {

public boolean handleFault(MessageContext messageContext)
        throws WebServiceClientException {
    return true;
}

public boolean handleRequest(MessageContext messageContext)
        throws WebServiceClientException {
     TransportContext context = TransportContextHolder.getTransportContext();
     HttpComponentsConnection connection =(HttpComponentsConnection) context.getConnection();
     connection.addRequestHeader("name", "suman");

    return true;
}

public boolean handleResponse(MessageContext messageContext)
        throws WebServiceClientException {
    return true;
}

}
配置:

    <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
    ...
    <property name="interceptors">
        <list>
            <bean class="com.blah.AddHttpHeaderInterceptor" />
        </list>
    </property>
</bean>

...

ClientInterceptor
非常适合静态标题值。但是,当每个请求应用不同的值时,不可能使用它。在这种情况下,
WebServiceMessageCallback
非常有用:

final String dynamicParameter = //...

webServiceOperations.marshalSendAndReceive(request, 
    new WebServiceMessageCallback() {
        void doWithMessage(WebServiceMessage message) {
            TransportContext context = TransportContextHolder.getTransportContext();
            CommonsHttpConnection connection = (CommonsHttpConnection) context.getConnection();
            PostMethod postMethod = connection.getPostMethod();
            postMethod.addRequestHeader( "fsreqid", dynamicParameter );
        }
}

以下片段已经用Spring 4.0进行了测试。它将
WebServiceMessageCallback
附加到
org.springframework.ws.client.core.WebServiceTemplate

final String DYNAMICVALUE = "myDynamo";

WebServiceMessageCallback wsCallback = new WebServiceMessageCallback() {           
       public void doWithMessage(WebServiceMessage message) {
            try {
                        SoapMessage soapMessage = (SoapMessage)message;
                        SoapHeader header = soapMessage.getSoapHeader();
                        header.addAttribute(new QName("myHeaderElement"), DYNAMICVALUE);                        
            } catch (Exception e) {
                        e.printStackTrace();
            }
       }
};

JAXBElement<MyWsResponse> response = (JAXBElement<MyWsResponse>)
        wsTemplate.marshalSendAndReceive(MyWsOP, wsCallback);
最终字符串DYNAMICVALUE=“myDynamo”;
WebServiceMessageCallback wsCallback=新建WebServiceMessageCallback(){
公共无效doWithMessage(WebServiceMessage消息){
试一试{
SoapMessage SoapMessage=(SoapMessage)消息;
SoapHeader=soapMessage.getSoapHeader();
addAttribute(新的QName(“myHeaderElement”)、DYNAMICVALUE;
}捕获(例外e){
e、 printStackTrace();
}
}
};
JAXBElement响应=(JAXBElement)
wsTemplate.MarshalSendReceive(MyWsOP,wsCallback);

Spring的webServiceTemplate.MarshallSendReceive(请求)方法在内部使用HttpComponents消息发送器通过网络发送SOAP消息,这进一步使用WebServiceConnection与服务器建立http连接。您所要做的就是编写自己的定制HttpComponentMessageSender,并在postMethod中设置cookie

客户发件人代码:

    package com.swap.ws.sender;

import java.io.IOException;
import java.net.URI;

import javax.annotation.Resource;

import org.apache.http.client.methods.HttpPost;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.ws.transport.WebServiceConnect ion;
import org.springframework.ws.transport.http.HttpComponen tsConnection;

/**
* 
* @author swapnil Z
*/
@Service("urlMessageSender")
public class CustomHttpComponentsMessageSender extends
org.springframework.ws.transport.http.HttpComponen tsMessageSender {
private static Logger _logger = Logger.getLogger("");


@Override
public WebServiceConnection createConnection(URI uri) throws IOException {
String cookie = null;
HttpComponentsConnection conn = (HttpComponentsConnection) super
.createConnection(uri);
HttpPost postMethod = conn.getHttpPost();
cookie = "<Your Custom Cookie>";

postMethod.addHeader("Cookie", cookie);

return conn;
}
}
package com.swap.ws.sender;
导入java.io.IOException;
导入java.net.URI;
导入javax.annotation.Resource;
导入org.apache.http.client.methods.HttpPost;
导入org.apache.log4j.Logger;
导入org.springframework.stereotype.Service;
导入org.springframework.ws.transport.WebServiceConnect;
导入org.springframework.ws.transport.http.HttpComponen tsConnection;
/**
* 
*@author swapnil Z
*/
@服务(“urlMessageSender”)
公共类CustomHttpComponentMessageSender扩展
org.springframework.ws.transport.http.HttpComponen tsMessageSender{
私有静态记录器_Logger=Logger.getLogger(“”);
@凌驾
公共WebServiceConnectionCreateConnection(URI)引发IOException{
字符串cookie=null;
HttpComponentsConnection conn=(HttpComponentsConnection)超级
.createConnection(uri);
HttpPost postMethod=conn.getHttpPost();
曲奇=”;
postMethod.addHeader(“Cookie”,Cookie);
返回连接;
}
}
弹簧配置:

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

<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshalle r">
<property name="contextPath" value="com.swap.provision" />
</bean>

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServi ceTemplate">
<constructor-arg ref="messageFactory" />
<property name="marshaller" ref="marshaller"></property>
<property name="unmarshaller" ref="marshaller"></property>
<property name="messageSender" ref="urlMessageSender"/>
<property name="defaultUri" value=<Server URL> />
</bean>


在此之后,我只需获取BeanWebServiceTemplate并调用MarshallSendReceive方法。因此,在进行HTTP调用之前,每个请求都将设置其自定义cookie。

当使用spring integration 3和spring integration ws时,可以使用以下代码来处理请求:

public boolean handleRequest(MessageContext messageContext)
        throws WebServiceClientException {
    TransportContext context = TransportContextHolder.getTransportContext();
    HttpUrlConnection connection = (HttpUrlConnection) context
    .getConnection();
    connection.getConnection().addRequestProperty("HEADERNAME",
    "HEADERVALUE");

    return true;
}
拦截器可以通过以下方式连接到出站网关:

<ws:outbound-gateway ...            
        interceptor="addPasswordHeaderInterceptor" >
</ws:outbound-gateway>

<bean id="addPasswordHeaderInterceptor class="com.yourfirm.YourHttpInterceptor" />


实际上,它是的答案的更新版本,但提供了一个新的SpringWSAPI、Java8快捷方式,并关心使用单独的方法创建
WebServiceMessageCallback
实例

我认为这是更明显和自给自足的

final class Service extends WebServiceGatewaySupport {

    /**
     * @param URL       the URI to send the message to
     * @param payload   the object to marshal into the request message payload
     * @param headers   HTTP headers to add to the request
     */
    public Object performRequestWithHeaders(String URL, Object payload, Map<String, String> headers) {
        return getWebServiceTemplate()
                .marshalSendAndReceive(URL, payload, getRequestCallback(headers));
    }

    /**
     * Returns a {@code WebServiceMessageCallback} instance with custom HTTP headers.
     */
    private WebServiceMessageCallback getRequestCallback(Map<String, String> headers) {
        return message -> {
            TransportContext context = TransportContextHolder.getTransportContext();
            HttpUrlConnection connection = (HttpUrlConnection)context.getConnection();
            addHeadersToConnection(connection, headers);
        };
    }

    /**
     * Adds all headers from the {@code headers} to the {@code connection}.
     */
    private void addHeadersToConnection(HttpUrlConnection connection, Map<String, String> headers){
        headers.forEach((name, value) -> {
            try {
                connection.addRequestHeader(name, value);
            } catch (IOException e) {
                e.printStackTrace(); // or whatever you want
            }
        });
    }

}
最终类服务扩展了WebServiceGatewaySupport{
/**
*@param URL发送消息的URI
*@param payload要封送到请求消息有效负载中的对象
*@param headers要添加到请求的HTTP头
*/
公共对象performRequestWithHeaders(字符串URL、对象负载、映射头){
返回getWebServiceTemplate()
.marshalSendAndReceive(URL、有效负载、getRequestCallback(标头));
}
/**
*返回带有自定义HTTP头的{@code WebServiceMessageCallback}实例。
*/
私有WebServiceMessageCallback getRequestCallback(映射头){
返回消息->{
TransportContext上下文=TransportContextHolder.getTransportContext();
HttpUrlConnection连接=(HttpUrlConnection)context.getConnection();
添加HeadersToConnection(连接、标题);
};
}
/**
*将{@code headers}中的所有头添加到{@code connection}。
*/
私有void addHeadersToConnection(HttpUrlConnection连接,映射头){
headers.forEach((名称、值)->{
试一试{
connection.addRequestHeader(名称、值);
}捕获(IOE异常){
e、 printStackTrace();//或任何您想要的
}
});
}
}

java 1.8的示例方法:如何添加HTTP头:

public void executeObjectWebservice(String id) {
        ExecuteObject request = new ExecuteObject();
        getWebServiceTemplate().marshalSendAndReceive("http://url/webservice-test/uc4ws",
                new ObjectFactory().createExecuteObject(request), new WebServiceMessageCallback() {
                    public void doWithMessage(WebServiceMessage message) throws IOException {
                        TransportContext context = TransportContextHolder.getTransportContext();
                        HttpUrlConnection connection = (HttpUrlConnection) context.getConnection();
                        connection.addRequestHeader("ID", id);
                    }
                });    
        }
说明: 使用getWebServiceTemplate()

第一个参数是URI,第二个参数是随请求一起发送的对象。作为第三个参数,您可以添加为函数

new WebServiceMessageCallback()
在此处,您将覆盖
公共无效doWithMessage
。在发送请求之前调用此方法。在中,您可以通过访问消息并添加请求标头

TransportContext context = TransportContextHolder.getTransportContext();
HttpUrlConnection connection = (HttpUrlConnection) context.getConnection();
connection.addRequestHeader("ID", id);

很好的回答,对于将来的用户,使用HttpComponentsConnection而不是CommonHttpConnection,因为它已经被弃用了。它在运行JUnit测试时有效吗?在我的例子中,这不是因为
context.getConnection()
返回
MockSenderConnection
。我正在使用
MockWebServiceServer
进行单元测试。为了更好地扩展
ClientInterceptorAdapter
,请检查
connection
是否是
HeadersAwareSenderWebServiceConnection
的实例,在使用不同传输的情况下。此解决方案比使用客户端拦截器更灵活。我想,它应该是首选的。我在这一行得到了以下异常java.lang.ClassCastException: