doedje / jquery.soap

This script uses $.ajax to send a SOAP:Envelope. It can take XML DOM, XML string or JSON as input and the response can be returned as either XML DOM, XML string or JSON too.
352 stars 148 forks source link

Problem with Content-Type: multipart/related; type="application/xop+xml"; #92

Closed tilmanginzel closed 8 years ago

tilmanginzel commented 8 years ago

Hey guys, I am having trouble to read the <soap:Envelope> from the response I am receiving. I am using jquery.soap.js version 1.6.7 and jquery version 1.11.3.

First of all, here is my $.soap call.

$.soap({
    url: 'myurl',
    data: mydata,
    appendMethodToUrl: false,
    enableLogging: true,
    soap12: true,
    ...

    success: function(SOAPResponse) {
        console.log("success");
        console.log(SOAPResponse);
    },
    error: function(SOAPResponse) {
        console.log("error");
        console.log(SOAPResponse);
    }
});

The corresponding raw HTTP request:

POST /webservice/api?wsdl HTTP/1.1
Host: localhost:8443
Connection: keep-alive
Content-Length: 503
Accept: application/xml, text/xml, */*; q=0.01
Origin: http://localhost:63342
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/45.0.2454.101 Chrome/45.0.2454.101 Safari/537.36
Content-Type: application/soap+xml; charset=UTF-8
DNT: 1
Accept-Encoding: gzip, deflate
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <tns:login xmlns:tns="mynamespace">
            <data>data</data>
        </tns:login>
    </soap:Body>
</soap:Envelope>

And this is the response:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST
Content-Type: multipart/related; type="application/xop+xml"; boundary="uuid:4d5034cf-be88-457f-a80f-ad0300ea276d"; start="<root.message@cxf.apache.org>"; start-info="application/soap+xml"
Content-Length: 520
Date: Wed, 25 Nov 2015 16:46:34 GMT

--uuid:4d5034cf-be88-457f-a80f-ad0300ea276d
Content-Type: application/xop+xml; charset=UTF-8; type="application/soap+xml"
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Body><ns2:loginResponse xmlns:ns2="mynamespace"><data>2e727q37-4048-4275-b7e2-e1f896c46eb3</data></ns2:loginResponse></soap:Body></soap:Envelope>
--uuid:4d5034cf-be88-457f-a80f-ad0300ea276d--

So the problem is that the <soap:Envelope> ist wrapped inside a multipart message. This results in a parseerror and the error callback is invoked. Is there anything I am missing? Or is it simply not possible to read multipart messages? Unfortunately this is something I cannot fix on the server side.

An acceptable workaround could be to extract the envelope by hand, e.g. with a regex. Is there a possibility to manipulate the response before the error callback is invoked? Any help is appreciated. Thanks!

doedje commented 8 years ago

As far as I can tell, looking at your request and response (thanx for that, big help!) and the code for $.soap you get an error from the underlying $.ajax call...

To explain a little about what is going on, so you can do some coding and testing:

In $.soap line# 265:

return $.ajax({
           // options....
           dataType: "xml",
           // more options....

you see the actual $.ajax call which has no error or success function, instead it returns the jqXHR object back to line# 121:

return soapEnvelope.send({
          // options....
}).done(function(data, textStatus, jqXHR) {
          // deal with response when succesful
}).fail(function(jqXHR, textStatus, jqXHR) {
          // deal with an error....
});

So my guess is the $.ajax function wants to parse the response, because we said it would be dataType: "xml" but the parser fails. So to fix this you might want to try and outcomment line# 273:

dataType: "xml",

If that doesn't change things it might be worthwhile to look into using the browsers native XMLHttpRequest and skip using $.ajax (and thus $.soap) in your particular situation.

I hope you find this useful, please let me know your findings; if it just takes a tweak to improve $.soap overall I am always interested!

tilmanginzel commented 8 years ago

Thanks for your fast response! Outcommenting line 273 didn't help, but setting dataType: "text" did. Now the success callback is invoked and I get a SOAPResponse with its content as plain text.

I was able to extract the <soap:Envelope> with a regex and replace the content of the SOAPResponse afterwards.

success: function(SOAPResponse) {
    var regex = "<soap:Envelope.*soap:Envelope>";
    var content = SOAPResponse.content.match(regex)[0];
    SOAPResponse.content = content;
    console.log(SOAPResponse.toXML());
},

Now I am getting a well-formed XML structure which can be used for further parsing or whatever I want. Seems a little bit hacky but I guess its the best workaround I can find. Maybe I will dig into the native XMLHttpRequest some time, but right now this should do it.

doedje commented 8 years ago

happy to hear you're okay!