web-dev-qa-db-fra.com

La valeur de l'en-tête HTTP 'SOAPAction' n'a pas été reconnue par le serveur.

Lorsque j'envoie une demande SOAP au serveur, il renvoie l'erreur suivante, bien que j'envoie une demande similaire à l'aide de SoapUI, ce qui fonctionne. Il semble que j'ai besoin de changer ma demande SOAP pour celle que j'envoie à l'aide de SoapUI.WSDLest ici .

 [ truncated ] System.Web.Services.Protocols.SoapException : The value of the 
    HTTP header ' SOAPAction ' was not recognized by the server . \ r \ n at 
    System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest ( ) 
    \ r \ n at System.Web.Servic

J'envoie la demande suivante en utilisant Java

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <ns2:SearchFlights xmlns:ns2="ElysArres.API">
         <ns2:SoapMessage>
            <ns2:Username>Test</ns2:Username>
            <ns2:Password>TestPassword</ns2:Password>
            <ns2:LanguageCode>EN</ns2:LanguageCode>
            <ns2:Request>
               <ns2:Departure>ONT</ns2:Departure>
               <ns2:Destination>EWR</ns2:Destination>
               <ns2:DepartureDate>2016-01-20</ns2:DepartureDate>
               <ns2:ReturnDate>2016-01-28</ns2:ReturnDate>
               <ns2:NumADT>1</ns2:NumADT>
               <ns2:NumINF>0</ns2:NumINF>
               <ns2:NumCHD>0</ns2:NumCHD>
               <ns2:CurrencyCode>EUR</ns2:CurrencyCode>
               <ns2:WaitForResult>true</ns2:WaitForResult>
               <ns2:NearbyDepartures>true</ns2:NearbyDepartures>
               <ns2:NearbyDestinations>true</ns2:NearbyDestinations>
               <ns2:RROnly>false</ns2:RROnly>
               <ns2:MetaSearch>false</ns2:MetaSearch>
            </ns2:Request>
         </ns2:SoapMessage>
      </ns2:SearchFlights>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Je peux envoyer la requête suivante en utilisant SoapUI et il fonctionne

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:els="ElsyArres.API">
   <soap:Header/>
   <soap:Body>
      <els:SearchFlights>
         <els:SoapMessage>
            <els:Username>Test</els:Username>
            <els:Password>TestPassword</els:Password>
            <els:LanguageCode>EN</els:LanguageCode>
            <els:Request>
               <els:Departure>ONT</els:Departure>
               <els:Destination>EWR</els:Destination>
               <els:DepartureDate>2016-01-20</els:DepartureDate>
               <els:ReturnDate>2016-01-28</els:ReturnDate>
               <els:NumADT>1</els:NumADT>
               <els:NumINF>0</els:NumINF>
               <els:NumCHD>0</els:NumCHD>
               <els:CurrencyCode>EUR</els:CurrencyCode>
               <els:WaitForResult>true</els:WaitForResult>
               <els:NearbyDepartures>true</els:NearbyDepartures>
               <els:NearbyDestinations>true</els:NearbyDestinations>
               <els:RROnly>false</els:RROnly>
               <els:MetaSearch>false</els:MetaSearch>
            </els:Request>
         </els:SoapMessage>
      </els:SearchFlights>
   </soap:Body>
</soap:Envelope>

Je ne suis pas sûr de savoir comment faire la demande que je crée avec Java, identique à celle que j'envoie avec SoapUI.

Code

Recherche de vols

@XmlRootElement(name = "SearchFlights")
@XmlAccessorType(XmlAccessType.FIELD)
public class SearchFlights {
    @XmlElement(name = "SoapMessage")
    private SoapMessage soapMessage;

    getter and setter

SoapMessage

@XmlRootElement(name = "SoapMessage")
@XmlAccessorType(XmlAccessType.FIELD)
public class SoapMessage {
    @XmlElement(name = "Username")
    private String username;
    @XmlElement(name = "Password")
    private String password;
    @XmlElement(name = "LanguageCode")
    private String languageCode;
    @XmlElement(name = "Request")
    private Request request;

    getters and setters

Demande

@XmlRootElement(name = "Request")
@XmlAccessorType(XmlAccessType.FIELD)
public class Request {
    @XmlElement(name = "Departure")
    private String departure;
    @XmlElement(name = "Destination")
    private String destination;
    @XmlElement(name = "DepartureDate")
    private String departureDate;
    @XmlElement(name = "ReturnDate")
    private String returnDate;
    @XmlElement(name = "NumADT")
    private int numADT;
    @XmlElement(name = "NumINF")
    private int numInf;
    @XmlElement(name = "NumCHD")
    private int numCHD;
    @XmlElement(name = "CurrencyCode")
    private String currencyCode;
    @XmlElement(name = "WaitForResult")
    private boolean waitForResult;
    @XmlElement(name = "NearByDepartures")
    private boolean nearByDepartures;
    @XmlElement(name = "NearByDestinations")
    private boolean nearByDestinations;
    @XmlElement(name = "RROnly")
    private boolean rronly;
    @XmlElement(name = "MetaSearch")
    private boolean metaSearch;

getters and setters

package-info.Java

@XmlSchema( 
    namespace = "ElsyArres.API",
    elementFormDefault = XmlNsForm.QUALIFIED) 
package com.myproject.flights.wegolo;

import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

jaxb.index

SearchFlights
Flight
Flights
Leg
Legs
Outbound
Request
Response
SoapMessage

Code d'envoi de la demande

import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConstants;

import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
......
    // populate searchFlights and other classes to create request
    try {
        SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(
                MessageFactory.newInstance());
        messageFactory.afterPropertiesSet();

        WebServiceTemplate webServiceTemplate = new WebServiceTemplate(
                messageFactory);
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();

        marshaller.setContextPath("com.myproject.flights.wegolo");
        marshaller.afterPropertiesSet();

        webServiceTemplate.setMarshaller(marshaller);
        webServiceTemplate.afterPropertiesSet();

        Response response = (Response) webServiceTemplate
                .marshalSendAndReceive(
                        "http://www5v80.elsyarres.net/service.asmx",
                        searchFlights);

        Response msg = (Response) response;
        System.err.println("Wegolo >>>"
                + msg.getFlights().getFlight().size());
    } catch (Exception s) {
        s.printStackTrace();
    }

Mise à jour

J'ai supprimé package-info.Java et j'ai réussi à utiliser le code suggéré, mais le même en-tête est toujours envoyé.

Response response = (Response) webServiceTemplate
                    .marshalSendAndReceive(
                            "http://www5v80.elsyarres.net/service.asmx",
                            searchFlights,
                            new WebServiceMessageCallback() {
                                public void doWithMessage(WebServiceMessage message) 
                                {
                                    ((SoapMessage)message).setSoapAction("http://www5v80.elsyarres.net/searchFlights");
                                }
                           }
                       );

 enter image description here

5
Daniel Newtown

SOAP version 1.1 requiert un en-tête HTTP dans votre demande SOAP pour spécifier l'action SOAP. Ce n'est pas dans le XML réel, mais dans la requête (dans l'en-tête HTTP). C'est pourquoi vous ne voyez aucune différence entre votre xml de requête SoapUI et la requête que vous envoyez à l'aide de WebServiceTemplate. Soap 1.2 vous permet de le définir en tant qu'attribut sur le type de support, mais cela n'est pas valable pour un serveur 1.1. Notez que, selon la spécification , la valeur que vous utilisez ne doit pas nécessairement être résolue.

SOAP n'impose aucune restriction quant au format ou à la spécificité de l'URI, ni de sa résolution. Un client HTTP DOIT utiliser ce champ d’en-tête lorsqu’il émet une demande HTTP SOAP.

Habituellement, c'est spécifié dans votre WSDL, quelque chose comme (tiré de ici ):

<soap:operation
        soapAction="http://www5v80.elsyarres.net/searchFlights"
        style="document" />

Si ce n'est pas dans votre WSDL, vous pouvez l'ajouter en utilisant l'annotation action au printemps dans votre classe de point de terminaison webservice.

@Endpoint
public class MyFlightEndpoint{
    @Action("http://www5v80.elsyarres.net/searchFlights")
    public SearchFlights request() {
        ...
    }
}

Si c'est dans votre WSDL, vous voudrez placer cette valeur dans votre en-tête HTTP du côté client. Pour ce faire, vous devez ensuite accéder au message côté client après sa création, mais avant son envoi afin d'ajouter l'en-tête de l'action. Spring fournit une interface de rappel de message pour cela, décrite ici . Ce que vous voudrez faire est quelque chose comme:

Response response = (Response) webServiceTemplate
            .marshalSendAndReceive(
                    "http://www5v80.elsyarres.net/service.asmx",
                    searchFlights,
                    new WebServiceMessageCallback() {
                        public void doWithMessage(WebServiceMessage message) 
                        {
                            ((SoapMessage)message).setSoapAction("http://www5v80.elsyarres.net/searchFlights");
                        }
                   }
               );

Il y a une discussion sur SOAP en-têtes d'action ici , et le point (ou l'absence de point) pour eux si vous voulez en savoir plus.

Edit: Donc, en regardant le WSDL ici:

<soap:operation soapAction="ElsyArres.API/SearchFlights" style="document"/>

vous voudrez l'action suivante:

ElsyArres.API/searchFlights

Maintenant, il suffit de mettre à jour le code pour le lire

((SoapMessage)message).setSoapAction("ElsyArres.API/searchFlights");

et vous êtes prêt à partir!

Edit 2: Je remarque également que le service auquel vous vous connectez accepte les connexions SOAP 1.2, lorsque vous utilisez SOAP 1.1. Vous pouvez forcer votre client à utiliser SOAP 1.2 en le configurant dans votre usine.

messageFactory.setSoapVersion(SoapVersion.SOAP_12);
messageFactory.afterPropertiesSet();

Il semble que le serveur utilise le même point de terminaison, ce qui devrait donc être le seul changement.

10
AndyN

Une autre façon d’ajouter l’en-tête SOAPAction lors de l’utilisation de WebServiceGatewaySupport consiste à effectuer les opérations suivantes:

getWebServiceTemplate().marshalSendAndReceive(request, new SoapActionCallback("http://httpheader/"));

Ceci utilise messageFactory.setSoapVersion(SoapVersion.SOAP_12);

0
adnans

J'ai eu le même problème, ma solution était:

  @Configuration
  public class SoapConfiguration {
      private static final String SOAP_1_2_PROTOCOL= "SOAP 1.2 Protocol";

  @Bean
   public WebServiceTemplate webServiceTemplate() throws Exception {

   SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(javax.xml.soap.MessageFactory.newInstance(SOAP_1_2_PROTOCOL));
   messageFactory.setSoapVersion(SoapVersion.SOAP_12);
   messageFactory.afterPropertiesSet();

   WebServiceTemplate webServiceTemplate = new WebServiceTemplate(
           messageFactory);
   Jaxb2Marshaller marshaller = new Jaxb2Marshaller();

   marshaller.setContextPath("YOUR_WSDL_GENERATED_PATH");
   marshaller.afterPropertiesSet();
   webServiceTemplate.setMarshaller(marshaller);
   webServiceTemplate.setUnmarshaller(marshaller);
   webServiceTemplate.afterPropertiesSet();
   return webServiceTemplate;
}

Et mon SoapService

@Service
@RequiredArgsConstructor
public class SoapDomainBoxService extends WebServiceGatewaySupport {
 private final WebServiceTemplate webServiceTemplate;

public void searchFlights(SearchFlights searchFlights) {

    String url = "YOUR.URL.asmx";
   Response response = (Response) webServiceTemplate.marshalSendAndReceive(url, searchFlights, new SoapActionCallback("ACTION.CALLBACK"));
}

Très important sur la création de l’usine de messagerie

   SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(javax.xml.soap.MessageFactory.newInstance(SOAP_1_2_PROTOCOL));
0
sashanet buryk