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

发布于 2024-11-02 18:37:11 字数 1424 浏览 2 评论 0原文

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

xttp://site.com 将提供主要的 php 文件 xttp://static.site.com 将提供 css 和 js xttp://content.site.com 将提供图像等

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

有关原因,请阅读下文。

但是,当我尝试时遇到问题通过 javascript 访问任何 css 规则。准确地说是 NS_ERROR_DOM_SECURITY_ERR 。这是一项相对较新的安全措施,与防止跨域脚本编写有关。

过去,有一些措施可以解决这个问题,包括关闭这种保护。这不再有效。

我的问题:

如果来自与主页不同的域,是否可以通过 javascript 访问正常加载的 css 规则?

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 能力相对较少。每个都有不同的硬件/托管要求。对每个选项进行微调不仅可以提供更好的性能,还可以降低托管成本,至少对我来说仍然是运行网站的最大成本之一。

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:

Is there any way to let Firefox and other browsers know that it should treat certain domains as being the same even though the domain names are different?

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

瑕疵 2024-11-09 18:37:11

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

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

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

或者甚至,如果您不考虑 < 上的任何内容code>static.site.com 保持敏感:

Access-Control-Allow-Origin: *

Mozilla 开发者网络<上提供了更多信息/a>.

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.

━╋う一瞬間旳綻放 2024-11-09 18:37:11

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

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

有时,如果您从无法控制 CORS 设置的位置提取 CSS,您仍然可以使用 标记获取 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;
}

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;
}
秋意浓 2024-11-09 18:37:11
document.domain = "site.com";

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文