Comment définir un en-tête HTTP personnalisé (et non SOAP) de manière dynamique côté client lorsque vous utilisez Spring-WS?
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();
CommonsHttpConnection connection = (CommonsHttpConnection) context.getConnection();
PostMethod postMethod = connection.getPostMethod();
postMethod.addRequestHeader( "fsreqid", "123456" );
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>
ClientInterceptor
fonctionne très bien pour la valeur d'en-tête statique. Mais il n'est pas possible de l'utiliser lorsqu'une valeur différente doit être appliquée pour chaque demande. Dans ce cas, WebServiceMessageCallback
est utile:
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 );
}
}
Lorsque vous utilisez Spring Integration 3 et Spring Integration-ws, vous pouvez utiliser le code suivant pour traiter la demande:
public boolean handleRequest(MessageContext messageContext)
throws WebServiceClientException {
TransportContext context = TransportContextHolder.getTransportContext();
HttpUrlConnection connection = (HttpUrlConnection) context
.getConnection();
connection.getConnection().addRequestProperty("HEADERNAME",
"HEADERVALUE");
return true;
}
L’Interceptor peut être connecté à la passerelle sortante de la manière suivante:
<ws:outbound-gateway ...
interceptor="addPasswordHeaderInterceptor" >
</ws:outbound-gateway>
<bean id="addPasswordHeaderInterceptor class="com.yourfirm.YourHttpInterceptor" />
La méthode webServiceTemplate.marshalSendAndReceive (request) de Spring utilise en interne HttpComponentsMessageSender pour envoyer le message SOAP sur le réseau, ce qui utilise également WebServiceConnection pour établir une connexion http avec le serveur. Tout ce que vous avez à faire est d'écrire votre propre HttpComponentsMessageSender et de définir le cookie dans postMethod.
Code expéditeur personnalisé:
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;
}
}
Configuration du printemps:
<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>
Après cela, je récupère simplement le bean webServiceTemplate et appelle la méthode marshalSendAndReceive. Ainsi, chaque cookie aura son cookie personnalisé défini avant de passer un appel HTTP.
En réalité, il s'agit d'une version mise à jour de la réponse de @Tomasz , mais elle fournit une nouvelle API Spring-WS, des raccourcis Java 8 et se préoccupe de la création d'une instance WebServiceMessageCallback
avec une méthode distincte.
Je crois que c'est plus évident et autosuffisant.
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
}
});
}
}
Exemple de méthode avec Java 1.8: Comment ajouter un en-tête 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);
}
});
}
Explication: Utilisez getWebServiceTemplate (). MarshalSendAndReceive comme décrit par exemple ici: https://spring.io/guides/gs/consuming-web-service/
Le premier paramètre est l'URI, le second est l'objet qui doit être envoyé avec la demande. En tant que troisième paramètre, vous pouvez ajouter une fonction
new WebServiceMessageCallback()
où vous remplacez le public void doWithMessage
. Cette méthode s'appelle avant la requête est envoyée. Vous pouvez accéder au message et ajouter un en-tête de demande via
TransportContext context = TransportContextHolder.getTransportContext();
HttpUrlConnection connection = (HttpUrlConnection) context.getConnection();
connection.addRequestHeader("ID", id);