PDA

View Full Version : xdomainrequest support



dolittle
22 Feb 2011, 8:54 AM
Is there a support for xdomainrequest using IE?
This feature is old in IE8 but I can't find info about it in extjs.

Thanks

neofraktal
1 Jun 2011, 3:24 AM
I'm also interested on xdomainrequest

charris
14 Oct 2011, 4:26 AM
+1 on the request to add support for Internet Explorer's (stupid, non-standard as usual) XDomainRequest object so that ExtJS can offer cross-origin/domain request (COR) support for all modern browsers.

http://en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing
http://msdn.microsoft.com/en-us/library/dd573303(v=vs.85).aspx

arthurakay
14 Oct 2011, 8:30 AM
...so that ExtJS can offer cross-origin/domain request

Isn't that exactly what JSONP does?

Furthermore, where would you like Sencha to add this capability? Ext.Ajax? That won't happen as (to my knowledge) other browsers don't support cross-domain AJAX calls (only JSONP) so the result would be an inconsistent implementation within the Sencha frameworks.

charris
14 Oct 2011, 9:15 AM
Hey Arthur, thanks for chiming in. Btw, I was planning to take you up on your tweet last week about Sencha devs meeting up at a bar in NYC, but something came up... Anyways, in regards to this feature request:

JSONP certainly works in several cases, but as you know, some browsers like MSIE don't allow GET URLs longer than ~2K characters; this puts a limit on the amount of data you can send back to the server that wouldn't be an issue with POST.

The XMLHttpRequest object in current versions of Chrome/FF/Safari (and I think iOS 5 + Android Browser 3) support cross-domain POSTing as long as the server uses the appropriate headers. There's a nice article about CORS here (http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/), and some more info here (http://enable-cors.org/). MSIE 8/9 does not; you have to use their silly XDomainRequest object instead of XMLHttpRequest.

You might argue that CORS is the future, not JSONP. It doesn't require any "tricks" like dynamically inserting script elements into the DOM, using an iframe etc. More importantly, there's a W3C spec for it: http://www.w3.org/TR/cors/. The server just needs to support the CORS HTTP headers (instead of wrapping responses in a JSONP callback).

So with the prospect of a spec/standard way of doing cross-domain GET+POST requests, and most browsers supporting it in some form already, it seems like Sencha should consider supporting it (which really only means using XDomainRequest on MSIE).

Thoughts? I'd be really curious to hear what Team Sencha thinks since you guys are really the pros when it comes to this stuff.

arthurakay
14 Oct 2011, 10:37 AM
I was planning to take you up on your tweet last week about Sencha devs meeting up at a bar in NYC, but something came up...

No worries... no one took me up on the offer, but there's always a next-time.

I would agree that older IE browsers present a problem regarding URL size limits, so JSONP obviously doesn't make the best choice. I normally suggest for that you create a server-side "router" class which takes your request (from the same domain) and does the cross-domain calls on the server. This alleviates any concern over IE's URL limits, and would also allow for a variety of return types (XML, JSON, etc).

I actually didn't know about the cross-domain AJAX requests being implemented by newer browsers. Thanks for sharing those links... you learn something new every day!

Keeping CORS in mind, I suppose that it does make sense to add this to the framework at some point. The problem still remains for older browsers - and it's not an easy problem to solve given that Sencha's mission is to have the same code work across ALL browsers.

I'm not on the engineering team, but I would bet this issue is somewhere on their radar. I'll see if I can poke one of them for a comment.

charris
14 Oct 2011, 10:53 AM
The "work on every browser" concern is definitely a valid point. And using a server-side "router" is a great idea. (Also a server-side reverse proxy would do the trick.)


I'll see if I can poke one of them for a comment.

Thanks--I'd love to hear their thoughts, but I'm sure everyone is extremely busy prepping for Austin and working on 4.1, so no worries if nobody gets back to you.

skirtle
15 Oct 2011, 7:56 AM
The "work on every browser" concern is definitely a valid point.

It wouldn't be unprecedented though. The LocalStorage proxy doesn't work in all browsers.

charris
17 Oct 2011, 7:41 AM
Wow, just noticed that Ext.data.Connection (http://docs.sencha.com/ext-js/4-0/#!/api/Ext.data.Connection-cfg-cors) API docs now mention a "cors" config param:

cors: Boolean. True to enable CORS support on the XHR object. Currently the only effect of this option is to use the XDomainRequest object instead of XMLHttpRequest if the browser is IE8 or above.

Not sure when this was added, but it's definitely not in the docs that came with the 4.0.6 download. Awesome!

basememara
3 Jan 2012, 6:33 AM
I have a different way of using CORS. Instead of using CORS to get cross-domain JSON data, I need it for embedding my application on other websites. This means I need Ext.Loader to be CORS compatible so it can dynamically load my script files when enabled (for requiring classes, MVC setup, plugins, etc).

Here is my scenario for using CORS: my application resides on a remote server with its own domain. In the Ext.application section, I have the appFolder property pointed to its own domain (so remote sites know where to access it when they embed my app). In the Apache server where my app resides, I have also enabled "cross-origin resource sharing":


Header set Access-Control-Allow-Origin *

Now websites and bloggers can paste the embed code for my Sencha app without copying any files. This means they will be referencing my app.js file from my remote web server (one Sencha app serving multiple websites).

This scenario works PERFECTLY when browsing various blogs and websites via Chrome or Firefox. BUT when viewing the sites with the latest IE, nothing loads and I get the following error:


SCRIPT575: Could not complete the operation due to error c00c023f.
ext-all-debug-w-comments.js, line 7805 character 17




/**
* Load a script file, supports both asynchronous and synchronous approaches
*
* @param {String} url
* @param {Function} onLoad
* @param {Object} scope
* @param {Boolean} synchronous
* @private
*/
loadScriptFile: function(url, onLoad, onError, scope, synchronous) {
var me = this,
noCacheUrl = url + (this.getConfig('disableCaching') ? ('?' + this.getConfig('disableCachingParam') + '=' + Ext.Date.now()) : ''),
fileName = url.split('/').pop(),
isCrossOriginRestricted = false,
xhr, status, onScriptError;


scope = scope || this;


this.isLoading = true;


if (!synchronous) {
onScriptError = function() {
onError.call(scope, "Failed loading '" + url + "', please verify that the file exists", synchronous);
};


if (!Ext.isReady && Ext.onDocumentReady) {
Ext.onDocumentReady(function() {
me.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
});
}
else {
this.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
}
}
else {
if (typeof XMLHttpRequest !== 'undefined') {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}


try {
xhr.open('GET', noCacheUrl, false);
xhr.send(null);
} catch (e) {
isCrossOriginRestricted = true;
}


status = (xhr.status === 1223) ? 204 : xhr.status; <<----ERROR HAPPENS HERE (LINE: 7805)


if (!isCrossOriginRestricted) {
isCrossOriginRestricted = (status === 0);
}


if (isCrossOriginRestricted
) {
onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; It's likely that the file is either " +
"being loaded from a different domain or from the local file system whereby cross origin " +
"requests are not allowed due to security reasons. Use asynchronous loading with " +
"Ext.require instead.", synchronous);
}
else if (status >= 200 && status < 300
) {
// Firebug friendly, file names are still shown even though they're eval'ed code
new Function(xhr.responseText + "\n//@ sourceURL=" + fileName)();


onLoad.call(scope);
}
else {
onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; please " +
"verify that the file exists. " +
"XHR status code: " + status, synchronous);
}


// Prevent potential IE memory leak
xhr = null;
}
},


I am not sure if it helps, but maybe these links can shed light and solve the Ext.Loader / IE / CORS issue?

http://www.enkeladress.com/article.php/internetexplorer9jscripterror
http://www.sencha.com/forum/showthread.php?162292-(CORS)-Cross-Origin-Resource-Sharing-requests
http://www.sencha.com/forum/showthread.php?150538-does-Ext.Ajax.request-support-the-cross-domain-request&highlight=CORS

charris
3 Jan 2012, 6:42 AM
I'm not sure if this is relevant, but if you look at the source (http://docs.sencha.com/ext-js/4-0/source/Connection.html#Ext-data-Connection-method-request) for Connection.request you'll see that it only tries to use a cross-domain request for IE 8+:

if ((options.cors === true || me.cors === true) && Ext.isIE && Ext.ieVersion >= 8) {
xhr = new XDomainRequest();
} else {
xhr = this.getXhrInstance();
}

basememara
3 Jan 2012, 6:57 AM
Thanks but I need this piece of code added for Ext.Loader.require (http://docs.sencha.com/ext-js/4-0/source/Loader.html#Ext-Loader):



/**
* Load a script file, supports both asynchronous and synchronous approaches
*
* @param {String} url
* @param {Function} onLoad
* @param {Object} scope
* @param {Boolean} synchronous
* @private
*/
loadScriptFile: function(url, onLoad, onError, scope, synchronous) {
var me = this,
noCacheUrl = url + (this.getConfig('disableCaching') ? ('?' + this.getConfig('disableCachingParam') + '=' + Ext.Date.now()) : ''),
fileName = url.split('/').pop(),
isCrossOriginRestricted = false,
xhr, status, onScriptError;

scope = scope || this;

this.isLoading = true;

if (!synchronous) {
onScriptError = function() {
onError.call(scope, "Failed loading '" + url + "', please verify that the file exists", synchronous);
};

if (!Ext.isReady && Ext.onDocumentReady) {
Ext.onDocumentReady(function() {
me.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
});
}
else {
this.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
}
}
else {
if (typeof XMLHttpRequest !== 'undefined') {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}

try {
xhr.open('GET', noCacheUrl, false);
xhr.send(null);
} catch (e) {
isCrossOriginRestricted = true;
}

status = (xhr.status === 1223) ? 204 : xhr.status;

if (!isCrossOriginRestricted) {
isCrossOriginRestricted = (status === 0);
}

if (isCrossOriginRestricted
//<if isNonBrowser>
&& !isPhantomJS
//</if>
) {
onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; It's likely that the file is either " +
"being loaded from a different domain or from the local file system whereby cross origin " +
"requests are not allowed due to security reasons. Use asynchronous loading with " +
"Ext.require instead.", synchronous);
}
else if (status >= 200 && status < 300
//<if isNonBrowser>
|| isPhantomJS
//</if>
) {
// Firebug friendly, file names are still shown even though they're eval'ed code
new Function(xhr.responseText + "\n//@ sourceURL=" + fileName)();

onLoad.call(scope);
}
else {
onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; please " +
"verify that the file exists. " +
"XHR status code: " + status, synchronous);
}

// Prevent potential IE memory leak
xhr = null;
}
},

basememara
9 Jan 2012, 7:36 AM
bump

...any chance we can get CORS enabled on Ext.Loader for the 4.1 release?

basememara
11 Jan 2012, 11:45 AM
I tried overriding the Ext.Loader singleton class as below, but no luck. The responseText is coming back blank, but is populated too late in the lifecycle. I am missing something, but I am not sure where ~o)



//ENABLE CORS WORKAROUND FOR SCRIPT LOADER
Ext.Loader.cors = true;
Ext.Loader.loadScriptFile = function(url, onLoad, onError, scope, synchronous) {
var me = this,
noCacheUrl = url + (this.getConfig('disableCaching') ? ('?' + this.getConfig('disableCachingParam') + '=' + Ext.Date.now()) : ''),
fileName = url.split('/').pop(),
isCrossOriginRestricted = false,
xhr, status, onScriptError;


scope = scope || this;

this.isLoading = true;

if (!synchronous) {
onScriptError = function() {
onError.call(scope, "Failed loading '" + url + "', please verify that the file exists", synchronous);
};

if (!Ext.isReady && Ext.onDocumentReady) {
Ext.onDocumentReady(function() {
me.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
});
}
else {
this.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
}
}
else {
//HANDLE CORS IN IE IF APPLICABLE
if (this.cors == true && Ext.isIE && Ext.ieVersion >= 8) {
xhr = new XDomainRequest();
xhr.onload = function() {
console.log(this.responseText);
};
xhr.onprogress = function() {};
xhr.onerror = function() {};
xhr.ontimeout = function() {};
try {
xhr.open('GET', noCacheUrl);
xhr.send(null);
xhr.status = 200;
} catch (e) {
isCrossOriginRestricted = true;
}
} else {
if (typeof XMLHttpRequest !== 'undefined') {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
try {
xhr.open('GET', noCacheUrl, false);
xhr.send(null);
} catch (e) {
isCrossOriginRestricted = true;
}
}

status = (xhr.status === 1223) ? 204 : xhr.status;

if (!isCrossOriginRestricted) {
isCrossOriginRestricted = (status === 0);
}

if (isCrossOriginRestricted
//<if isNonBrowser>
&& !isPhantomJS
//</if>
) {
onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; It's likely that the file is either " +
"being loaded from a different domain or from the local file system whereby cross origin " +
"requests are not allowed due to security reasons. Use asynchronous loading with " +
"Ext.require instead.", synchronous);
}
else if (status >= 200 && status < 300
//<if isNonBrowser>
|| isPhantomJS
//</if>
) {
// Firebug friendly, file names are still shown even though they're eval'ed code
new Function(xhr.responseText + "\n//@ sourceURL=" + fileName)();

onLoad.call(scope);
}
else {
onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; please " +
"verify that the file exists. " +
"XHR status code: " + status, synchronous);
}

// Prevent potential IE memory leak
xhr = null;
}
};


For context, I am trying this so I can embed my Sencha app in remote websites. The remote websites need to do cross-domain requests to dynamically load my app's Javascript files.

hendricd
11 Jan 2012, 4:53 PM
@basememara--

Some important constraints to consider for your IE8+ use case:

Synchronous requests are NOT supported with XDomainRequest.
Protocols must match between domains ( http !== https ), means no access.

basememara
11 Jan 2012, 5:50 PM
@hendricd I think you are SPOT ON!

I needed a synchronous call the way Ext.Loader.loadScriptFile was constructed. I even tried putting the logic for evaluating the remote script in the XDomainRequest's onload, but that fires much later. By the time that fires, the app is trying to make references to the needed classes already.



if (this.cors == true && Ext.isIE && Ext.ieVersion >= 8) {
xhr = new XDomainRequest();
xhr.onload = function() {
if (this.responseText != '') {
// Firebug friendly, file names are still shown even though they're eval'ed code
new Function(this.responseText + "\n//@ sourceURL=" + fileName)();

onLoad.call(scope);
}
};
xhr.onprogress = function() { };
xhr.onerror = function() { };
xhr.ontimeout = function() { };
xhr.timeout = 5000;
try {
xhr.open('GET', noCacheUrl);
xhr.send();
} catch (e) {
onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; It's likely that the file is either " +
"being loaded from a different domain or from the local file system whereby cross origin " +
"requests are not allowed due to security reasons. Use asynchronous loading with " +
"Ext.require instead.", synchronous);
}
} else {
if (typeof XMLHttpRequest !== 'undefined') {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
try {
xhr.open('GET', noCacheUrl, false);
xhr.send(null);
} catch (e) {
isCrossOriginRestricted = true;
}

status = (xhr.status === 1223) ? 204 : xhr.status;

if (!isCrossOriginRestricted) {
isCrossOriginRestricted = (status === 0);
}

if (isCrossOriginRestricted
//<if isNonBrowser>
&& !isPhantomJS
//</if>
) {
onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; It's likely that the file is either " +
"being loaded from a different domain or from the local file system whereby cross origin " +
"requests are not allowed due to security reasons. Use asynchronous loading with " +
"Ext.require instead.", synchronous);
}
else if (status >= 200 && status < 300
//<if isNonBrowser>
|| isPhantomJS
//</if>
) {
// Firebug friendly, file names are still shown even though they're eval'ed code
new Function(xhr.responseText + "\n//@ sourceURL=" + fileName)();

onLoad.call(scope);
}
else {
onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; please " +
"verify that the file exists. " +
"XHR status code: " + status, synchronous);
}


// Prevent potential IE memory leak
xhr = null;

rstuart
12 Mar 2012, 7:19 PM
Just to update everyone, CORS support will not work with any IE browser/XDomainRequest. See this (http://www.sencha.com/forum/showthread.php?186917-Does-the-CORS-option-in-Ext.data.Connection-v4.0.7-actually-work&p=753881).