With David's help, I found a few issues with my code.
I had dataType: 'json'
in my ajax set up. This is for the expected response, not the request. I removed it.
I used JSON.stringify( err )
to open up the xhr error object. This revealed the error I was missing originally: "Failed to read the 'responseXML' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'document' (was 'blob')."
I removed xhrFields: { responseType: 'blob' }
from my ajax set up. This allowed the xml file from the server to be read and land in the success handler. But still, the file was not loading.
I added a console log of xhr.getAllResponseHeaders()
which revealed that the Content-Disposition
was missing from xhr. I switched instead to content-type
to discern if the response was an XML file (application/octet-stream
) or JSON (application/json
).
After this, when trying to convert the blob to a file, I got this error: "Failed to execute 'createObjectURL' on 'URL': Overload resolution failed."
This question gave me the final answer I needed. The body of the response has to be explicitly converted to a blob object.
Here is the final, working code. (I have not tested the IE and Safari hacks.)
$.ajax( {
url: m_APIURL,
method: 'POST', type: 'POST',
data: JSON.stringify( formData ),
contentType: 'application/json',
crossDomain: true,
success: function( body, status, xhr )
{
console.log( "success! headers=" + xhr.getAllResponseHeaders() + " xhr=" + JSON.stringify( xhr ) ); // DEBUG
var header = xhr.getResponseHeader( 'content-type' );
if( header && header.indexOf( 'octet-stream' ) !== -1 )
{
// If success, returns a file. Trigger the file save.
var filename = 'license.xml';
var blob = new Blob( [body], { type: "application/octetstream" } );
if( typeof window.navigator.msSaveBlob !== 'undefined' )
{
// IE hack.
window.navigator.msSaveBlob( blob, filename );
}
else
{
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL( blob );
var a = document.createElement( "a" );
if( typeof a.download === 'undefined' )
{
// Safari hack.
window.location.href = downloadUrl;
}
else
{
a.href = downloadUrl;
a.download = filename;
document.body.appendChild( a );
a.click();
}
setTimeout( function() { URL.revokeObjectURL( downloadUrl ); }, 100 );
}
}
else
{
// If validation failed, returns JSON. Display the errors.
if( body )
{
if( ( body.ErrorMessage && body.ErrorMessage != "OK" ) || ( !body.Content || body.Content == '' ) )
{
alert( "Error getting license file. " + body.ErrorMessage );
}
else
{
alert( "Error getting license file. " + body.Content );
}
}
else
{
console.log( "returned null" ); //DEBUG
alert( "Error getting license file." );
}
}
},
error: function( err )
{
if( err != null && err.length > 0 )
{
console.log( "Error in response: " + JSON.stringify( err ) );
}
else
{
console.log( "Error in response but nothing returned." );
}
}
} );