Setting a custom HTTP header dynamically with Spring-WS client
Solution 1
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;
}
}
config:
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
...
<property name="interceptors">
<list>
<bean class="com.blah.AddHttpHeaderInterceptor" />
</list>
</property>
</bean>
Solution 2
ClientInterceptor
works great for static header value. But it is not possible to use it when a different value should be applied per each request. In that case WebServiceMessageCallback
is helpful:
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 );
}
}
Solution 3
When using spring integration 3 and spring integration-ws, the following code can be used for handling the request:
public boolean handleRequest(MessageContext messageContext)
throws WebServiceClientException {
TransportContext context = TransportContextHolder.getTransportContext();
HttpUrlConnection connection = (HttpUrlConnection) context
.getConnection();
connection.getConnection().addRequestProperty("HEADERNAME",
"HEADERVALUE");
return true;
}
The Interceptor can be connected to the outbound gateway in the following way:
<ws:outbound-gateway ...
interceptor="addPasswordHeaderInterceptor" >
</ws:outbound-gateway>
<bean id="addPasswordHeaderInterceptor class="com.yourfirm.YourHttpInterceptor" />
Solution 4
Example Method with java 1.8: How to add a HTTP header:
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);
}
});
}
Explanation: Use the getWebServiceTemplate().marshalSendAndReceive as described for example here: https://spring.io/guides/gs/consuming-web-service/
First parameter is the URI, second is the object which shall be send with the request. As third Parameter you can add as function
new WebServiceMessageCallback()
where you override the public void doWithMessage
. This method gets called before the request is sent. Within you can access the message and add a request Header through
TransportContext context = TransportContextHolder.getTransportContext();
HttpUrlConnection connection = (HttpUrlConnection) context.getConnection();
connection.addRequestHeader("ID", id);
Solution 5
Actually, it is an updated version of the @Tomasz's answer, but provides a new Spring-WS API, Java 8 shortcuts, and cares about creating a WebServiceMessageCallback
instance with a separate method.
I believe it is more obvious and self-sufficient.
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
}
});
}
}
user366735
Updated on March 05, 2020Comments
-
user366735 over 4 years
How do you set a custom HTTP header (not SOAP header) dynamically on the client side when using Spring-WS?
-
dardo almost 12 yearsGood answer, for users in the future, use HttpComponentsConnection instead of CommonsHttpConnection, as it has been deprecated.
-
Clint Eastwood almost 11 yearsThis solution is more flexible than using the client interceptor. IMHO, it should be the preferred one.
-
Saurabh Sharma about 10 yearsI'm getting following exception java.lang.ClassCastException: on this line context.getConnection() org.springframework.ws.transport.http.HttpServletConnection cannot be cast to org.springframework.ws.transport.http.CommonsHttpConnection
-
ZeroOne about 9 yearsThe question was "How do you set a custom HTTP header (not SOAP header)", but this answer actually adds a SOAP header, not an HTTP header.
-
ZeroOne about 9 yearsFYI,
org.springframework.ws.transport.http.CommonsHttpConnection
has been deprecated in favor oforg.springframework.ws.transport.http.HttpComponentsConnection
. -
Gooseman over 8 yearsI don't think this solution is going to work when running JUnit tests because
context.getConnection()
returnsMockSenderConnection
. I am usingMockWebServiceServer
for Unit testing. -
Gooseman over 8 yearsDoes it work when running JUnit tests? In my case it didn't because
context.getConnection()
returnsMockSenderConnection
. I am usingMockWebServiceServer
for Unit testing. -
Strinder over 7 yearsImportant: Setting a custom header (spring uses Sun HttpConnection now) must be enabled! System.setProperty("sun.net.http.allowRestrictedHeaders", "true") Or at VM startup: -Dsun.net.http.allowRestrictedHeaders=true
-
Admin over 6 yearsHow would I use this class? I have a service class generated from WSDL already.
-
Andrew Tobilko over 6 years@Pretty, use a URL and a payload specified there, and pass them here
-
Simon almost 6 yearsWhat don't you get?
-
Muhammad Hewedy almost 6 yearsBetter to extend
ClientInterceptorAdapter
-
Adriano Machado about 5 yearsEven better, check if
connection
is an instance ofHeadersAwareSenderWebServiceConnection
, in the case that a different transport is being used. -
alegria almost 3 yearsI personally found this more useful more my use case. Thanks sir.