Reputation: 136
I want to split up my website acrosss different servers and use subdomains for this purpose.
xttp://site.com will serve the main php file xttp://static.site.com will serve the css and js xttp://content.site.com will serve images and such
(xttp to prevent stackoverflow form thinking it is a url)
For the why, read below.
However, I run into a problem when I try to access through javascript any of the css rules. NS_ERROR_DOM_SECURITY_ERR to be precise. This is a relatively recent security measure and has to do with protection against cross domain scripting.
In the past, there were measures to fix this including just turning this protection off. This no longer works.
My question:
Is there anyway to access a normally loaded css rule through javascript if it is from a different domain then the main page?
The javascript:
MUI.getCSSRule=function(selector){
for(var ii=0;ii<document.styleSheets.length;ii++){
var mysheet=document.styleSheets[ii];
var myrules=mysheet.cssRules?mysheet.cssRules:mysheet.rules;
for(i=0;i<myrules.length;i++){
if(myrules[i].selectorText==selector){
return myrules[i]
}
}
}
return false
};
The javascript and css is loaded from the html with absolute paths
and the site url is "http://site.com"
Both domains are fully under my control but they are seperate machines (virtual for now but if it is even possible, in production they might not even be in the same location)
Rephrasing the question:
Why? So, I can easily use different servers with their own configuration, optimized for their task. A fast machine for the php, a simple one to serve the static stuff, a large machine for the content.
Why? Costs. A static server typically has little need for security against anyone downloading the files. It has little content so no need for an expensive array. Just load it in memory and serve from there. Memory itself can be limitted as well, try it. A PHP server, in my case at least, however will typically need lots of memory, need redundant storage, extensive logging. A content server will need massive storage and massive bandwidth but relatively little in the way of CPU power. Different hardware/hosting requirements for each. Finetuning each not only gives better performance but also reduces hosting costs, for me at least still one of the biggest costs of running a website.
Upvotes: 7
Views: 11228
Reputation: 109
I wrote a little function that will solve the loading problem cross-browser including FF. The comments on GitHub help explain usage. Full code at https://github.com/srolfe26/getXDomainCSS.
Disclaimer: The code below is jQuery dependent.
Sometimes, if you're pulling CSS from a place that you can't control the CORS settings you can still get the CSS with a <link>
tag, the main issue to be solved then becomes knowing when your called-for CSS has been loaded and ready to use. In older IE, you could have an on_load
listener run when the CSS is loaded.
Newer browsers seem to require old-fashioned polling to determine when the file is loaded, and have some cross-browser issues in determining when the load is satisfied. See the code below to catch some of those quirks.
/**
* Retrieves CSS files from a cross-domain source via javascript. Provides a jQuery implemented
* promise object that can be used for callbacks for when the CSS is actually completely loaded.
* The 'onload' function works for IE, while the 'style/cssRules' version works everywhere else
* and accounts for differences per-browser.
*
* @param {String} url The url/uri for the CSS file to request
*
* @returns {Object} A jQuery Deferred object that can be used for
*/
function getXDomainCSS(url) {
var link,
style,
interval,
timeout = 60000, // 1 minute seems like a good timeout
counter = 0, // Used to compare try time against timeout
step = 30, // Amount of wait time on each load check
docStyles = document.styleSheets // local reference
ssCount = docStyles.length, // Initial stylesheet count
promise = $.Deferred();
// IE 8 & 9 it is best to use 'onload'. style[0].sheet.cssRules has problems.
if (navigator.appVersion.indexOf("MSIE") != -1) {
link = document.createElement('link');
link.type = "text/css";
link.rel = "stylesheet";
link.href = url;
link.onload = function () {
promise.resolve();
}
document.getElementsByTagName('head')[0].appendChild(link);
}
// Support for FF, Chrome, Safari, and Opera
else {
style = $('<style>')
.text('@import "' + url + '"')
.attr({
// Adding this attribute allows the file to still be identified as an external
// resource in developer tools.
'data-uri': url
})
.appendTo('body');
// This setInterval will detect when style rules for our stylesheet have loaded.
interval = setInterval(function() {
try {
// This will fail in Firefox (and kick us to the catch statement) if there are no
// style rules.
style[0].sheet.cssRules;
// The above statement will succeed in Chrome even if the file isn't loaded yet
// but Chrome won't increment the styleSheet length until the file is loaded.
if(ssCount === docStyles.length) {
throw(url + ' not loaded yet');
}
else {
var loaded = false,
href,
n;
// If there are multiple files being loaded at once, we need to make sure that
// the new file is this file
for (n = docStyles.length - 1; n >= 0; n--) {
href = docStyles[n].cssRules[0].href;
if (typeof href != 'undefined' && href === url) {
// If there is an HTTP error there is no way to consistently
// know it and handle it. The file is considered 'loaded', but
// the console should will the HTTP error.
loaded = true;
break;
}
}
if (loaded === false) {
throw(url + ' not loaded yet');
}
}
// If an error wasn't thrown by this point in execution, the stylesheet is loaded, proceed.
promise.resolve();
clearInterval(interval);
} catch (e) {
counter += step;
if (counter > timeout) {
// Time out so that the interval doesn't run indefinitely.
clearInterval(interval);
promise.reject();
}
}
}, step);
}
return promise;
}
Upvotes: 0
Reputation: 1349
document.domain = "site.com";
Add to a JS file that is loaded before your CSS file. I would also add the HTTP headers suggested above.
Upvotes: -1
Reputation: 332736
CORS (cross-origin resource sharing) is a standard that allows sites to opt-in to access of resources cross-origin. I do not know if Firefox applies this to CSS yet; I know that it works for XMLHttpRequest, and it is intended that it will work for most other cross-domain request restrictions, but I haven't tested it in your precise use-case.
You can add following header to responses from static.site.com
to allow your main page to access the content of resources served from there:
Access-Control-Allow-Origin: http://site.com
Or even, if you don't consider any of your content on static.site.com
to be sensitive:
Access-Control-Allow-Origin: *
There's more information available on the Mozilla Developer Network.
Upvotes: 3