从不同的域加载CSS,并从Javascript访问它

Loading CSS from different domain, and accessing it from Javascript

本文关键字:并从 Javascript 访问 CSS 加载      更新时间:2023-09-26

我想将我的网站拆分到不同的服务器上,并为此使用子域。

xttp://site.com将提供主php文件xttp://static.site.com将提供css和jsxttp://content.site.com将提供图像和此类

(xttp防止stackoverflow表单认为它是一个url(

有关原因,请阅读以下内容

然而,当我试图通过javascript访问任何css规则时,我遇到了一个问题。NS_ERROR_DOM_SECURITY_ERR。这是一种相对较新的安全措施,与防止跨域脚本有关。

过去,有一些措施可以解决这个问题,包括关闭这种保护。现在已经不起作用了。

我的问题:

如果一个正常加载的css规则来自不同的域,那么是否可以通过javascript访问它?

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
};

javascript和css是从具有绝对路径的html加载的

网站url为"http://site.com">

这两个域都完全在我的控制之下,但它们是独立的机器(目前是虚拟的,但如果可能的话,在生产中它们甚至可能不在同一个位置(

重新表述问题:

有没有办法让Firefox和其他浏览器知道,即使域名不同,它也应该将某些域视为相同的

为什么?因此,我可以轻松地使用不同的服务器,并根据其任务进行优化。php的快速机器,提供静态内容的简单机器,内容的大型机器。

为什么?成本。静态服务器通常不需要对任何下载文件的人进行安全保护。它的内容很少,因此不需要昂贵的阵列。只要把它载入记忆,然后从那里发球。内存本身也可能受到限制,试试看。不过,至少在我的情况下,PHP服务器通常需要大量内存,需要冗余存储和大量日志记录。内容服务器将需要大量的存储和大量的带宽,但在CPU能力方面相对较少。每个都有不同的硬件/主机要求。对每一个进行微调不仅可以提供更好的性能,还可以降低托管成本,至少对我来说,这仍然是运营网站的最大成本之一。

CORS(跨来源资源共享(是一种允许站点选择跨来源访问资源的标准。我不知道Firefox是否将此应用于CSS;我知道它适用于XMLHttpRequest,而且它将适用于大多数其他跨域请求限制,但我还没有在您的确切用例中测试过它。

您可以将以下标题添加到static.site.com的响应中,以允许您的主页访问从那里提供的资源的内容:

Access-Control-Allow-Origin: http://site.com

甚至,如果你不认为static.site.com上的任何内容是敏感的:

Access-Control-Allow-Origin: *

Mozilla开发者网络提供了更多信息。

我写了一个小函数,可以解决包括FF在内的跨浏览器加载问题。GitHub上的评论有助于解释用法。完整代码位于https://github.com/srolfe26/getXDomainCSS.

免责声明:下面的代码依赖于jQuery。

有时,如果你从一个无法控制CORS设置的地方提取CSS,你仍然可以用<link>标签获得CSS,那么需要解决的主要问题就是知道你对CSS的调用何时已经加载并准备好使用。在较旧的IE中,可以在加载CSS时运行on_load侦听器。

较新的浏览器似乎需要老式的轮询来确定何时加载文件,并且在确定何时满足加载时存在一些跨浏览器问题。请参阅下面的代码,了解其中的一些怪癖。

/**
 * 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;
}
document.domain = "site.com";

添加到CSS文件之前加载的JS文件中。我还将添加上面建议的HTTP头。