views:

42

answers:

1

I have to make SOAP calls from javascript between different domains. On the server side there is a list of allowed domains, methods and headers which are included in the response by a filter. It works well (even between different domains) when the response code is 200 but when an exception is thrown on the server side the xhr object has 0 status instead of 500 and the responseText is empty. When using on the same domain the status and the responseText is ok.

The relevant code is as follows:

function onError(xhr, status, thrownError) {
    alert(xhr.status);
    alert(xhr.responseText);   
}

$.ajax({
    type: "POST",
    url: SOAPClient.Proxy,
    dataType: "xml",
    processData: false,
    data: content,
    context: context,
    contentType : SOAPClient.ContentType + "; " + SOAPClient.CharSet,
    error: onError,
    success: onSuccess,
    complete: onComplete,
    beforeSend: function(req) {
        req.setRequestHeader("Method", "POST");
        req.setRequestHeader("Content-Length", SOAPClient.ContentLength);
        req.setRequestHeader("SOAPServer", SOAPClient.SOAPServer);
        req.setRequestHeader("SOAPAction", soapReq.Action);
    }
});

I'm using jQuery-1.4.2. The allowed headers are "SOAPServer", "SOAPAction" and "Method". I tried it in FF 3.6.10 and Google Chrome 7.0.517.36

A: 

FF 3.6.8 returns an xhr.status === 0 when server replies with HTTP code if 301. The fix requires changeing httpSuccess function of $.ajax

To fix this I changed the httpSuccess of jQuery 1.4.2.

original:

httpSuccess: function( xhr ) {
    try {
        // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
        return !xhr.status && location.protocol === "file:" ||
            // Opera returns 0 when status is 304
            ( xhr.status >= 200 && xhr.status < 300 ) ||
            xhr.status === 304 || xhr.status === 1223 || xhr.status === 0;
    } catch(e) {}

    return false;
},

modified:

httpSuccess: function( xhr ) {
    try {
        // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
        return !xhr.status && location.protocol === "file:" ||
            // Opera returns 0 when status is 304
            ( xhr.status >= 200 && xhr.status < 300 ) ||
            xhr.status === 304 || xhr.status === 1223 ||
            ( xhr.status === 0 && xhr.statusText.toUpperCase() === 'OK');            
    } catch(e) {}

    return false;
},
Gutzofter
Thanks for your response but I'm afraid it won't work (i tried it). It can be seen from the logs that the server responds with 500 and I can also see that in firebug. It just that the actual response (ie the exception) is lost somewhere. In the meantime I built a simple javascript with native calls (no jquery involved) and got the same results. It seems that in case of cross origin resource sharing the browser doesn't forward the response if the status is other than 200. I've found an article about this problem when the client is implemented in flex.
Tibor
http://blog.widget-labs.com/2007/02/15/handling-web-service-exception-in-flex-code/
Tibor
I know it is not the same language/case but maybe the root of the problem is the same.
Tibor
did you say your are doing cross-domain request. `$.ajax` Won't work with cross-domain unless you do JSONP.
Gutzofter
You might be generating an exception on the server. Try catching it then format it for xml. send it back to client.
Gutzofter
as I said there is a filter on the server side which inspects the incoming requests and if it is a preflight request from a different domain then it responds by adding the needed headers (Access-Control-Allow-Origin etc). This way the client can communicate even from a different domain. The only problem is when the server responds with an exception (according to business logic). Even in this case the client machine receives the exception in form of an XML response (proved by examining the network traffic) but the browser somehow "removes" the actual response and the js client cannot access it
Tibor