Загрузка CSS из другого домена и доступ к нему из Javascript - PullRequest
4 голосов
/ 21 апреля 2011

Я хочу разделить свой веб-сайт по разным серверам и использовать для этого субдомены.

xttp: //site.com будет обслуживать основной файл php xttp: //static.site.com будет обслуживать CSS и JS xttp: //content.site.com будет обслуживать изображения и такие

(xttp, чтобы форма стека переполнения не думала, что это 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, по крайней мере, в моем случае, как правило, будет нуждаться в большом количестве памяти, избыточном хранилище, расширенном ведении журнала. Контент-серверу потребуются большие объемы хранилища и огромная пропускная способность, но относительно небольшая мощность процессора. Различные требования к оборудованию / хостингу для каждого. Настройка каждого из них не только повышает производительность, но и снижает стоимость хостинга, по крайней мере, для меня это одна из самых больших затрат на управление веб-сайтом.

Ответы [ 3 ]

2 голосов
/ 21 апреля 2011

CORS (совместное использование ресурсов из разных источников) - это стандарт, позволяющий сайтам получать доступ к ресурсам из разных источников.Я не знаю, применяет ли Firefox это к CSS еще;Я знаю, что он работает для XMLHttpRequest, и предполагается, что он будет работать для большинства других ограничений междоменных запросов, но я не проверял его в вашем конкретном сценарии использования.

Вы можете добавить следующий заголовокна ответы от static.site.com, чтобы разрешить вашей главной странице доступ к контенту обслуживаемых ресурсов:

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

Или даже, если вы не считаете какой-либо контент на static.site.com конфиденциальным:

Access-Control-Allow-Origin: *

Более подробная информация доступна в Mozilla Developer Network .

0 голосов
/ 29 апреля 2016

Я написал небольшую функцию, которая решит кросс-браузерную проблему загрузки, включая FF.Комментарии к GitHub помогают объяснить использование.Полный код на https://github.com/srolfe26/getXDomainCSS.

Отказ от ответственности: Код ниже зависит от jQuery.

Иногда, если вы вытаскиваете CSS из места, которое вы не можете контролироватьВ настройках CORS вы все еще можете получить CSS с тегом <link>, и основной проблемой, которая будет решена, станет знание того, когда ваш запрашиваемый CSS был загружен и готов к использованию.В более старых версиях IE вы могли запускать слушатель on_load при загрузке CSS.

Более новые браузеры, похоже, требуют старомодного опроса, чтобы определить, когда файл загружается, и могут иметь некоторые проблемы с браузеромопределение, когда нагрузка будет удовлетворена.Посмотрите код ниже, чтобы поймать некоторые из этих причуд.

/**
 * 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;
}
0 голосов
/ 22 июня 2011
document.domain = "site.com";

Добавить в JS-файл, который загружается перед вашим CSS-файлом.Я также добавил бы предложенные выше заголовки HTTP.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...