CDN başarısız olursa yerel stil sayfasına (komut dosyası değil) nasıl geri dönülür?


108

Bir CDN'deki jQuery Mobile stil sayfasına bağlanıyorum ve CDN başarısız olursa stil sayfasının yerel sürümüne geri dönmek istiyorum. Komut dosyaları için çözüm iyi bilinir:

<!-- Load jQuery and jQuery mobile with fall back to local server -->
<script src="http://code.jquery.com/jquery-1.6.3.min.js"></script>
<script type="text/javascript">
  if (typeof jQuery == 'undefined') {
    document.write(unescape("%3Cscript src='jquery-1.6.3.min.js'%3E"));
  }
</script>

Bir stil sayfası için benzer bir şey yapmak istiyorum:

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css" />

Benzer bir yaklaşımın elde edilip edilemeyeceğinden emin değilim çünkü tarayıcının bir komut dosyasını bağlarken bir komut dosyası yüklerken yaptığı gibi aynı şekilde engelleyip engellemediğinden emin değilim (belki bir komut dosyası etiketine bir stil sayfası yüklemek ve daha sonra sayfaya enjekte edin)?

Öyleyse sorum şu: Bir CDN başarısız olursa bir stil sayfasının yerel olarak yüklendiğinden nasıl emin olabilirim?


2
Bunun mümkün olup olmadığını bilmek isterim ... CDN'nin çalışmaması konusunda gerçekten endişeliysem, sadece yerel barındırma kullanırdım.
Fosco

2
@Stefan Kendall, bence doğru ifade, sitesinin çökme olasılığının bir CDN'den daha fazla olacağı yönünde
Shawn Mclean

Yanıtlar:


63

Tarayıcılar arası test edilmedi ama bunun işe yarayacağını düşünüyorum. Yine de jquery yükledikten sonra olması gerekecek, yoksa onu düz Javascript ile yeniden yazman gerekecek.

<script type="text/javascript">
$.each(document.styleSheets, function(i,sheet){
  if(sheet.href=='http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css') {
    var rules = sheet.rules ? sheet.rules : sheet.cssRules;
    if (rules.length == 0) {
      $('<link rel="stylesheet" type="text/css" href="path/to/local/jquery.mobile-1.0b3.min.css" />').appendTo('head');
    }
 }
})
</script>

iyi bir çözüm, ele almadığı bir sorun, CDN'nin yüklenemeyecek kadar yavaş olması ... belki bir tür zaman aşımı olabilir mi?
GeorgeU

2
İçin code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css , ben düzgün yüklenmiş oldu rağmen kuralları = null olsun. Chrome 26 kullanıyorum ve bunun nedeni komut dosyasının etki alanları arası olması mı?
simplfuzz

8
Çözüm tüm CDN'ler / Stil Sayfaları için gerçekten çalışmıyor, örneğin CSSStyleSheetbootstrapcdn.com'dan gelen js nesnelerinin tümü tarayıcımda boş rulesve cssRulesalanlara sahip (Chrome 31). UPD : aslında bir çapraz etki alanı sorunu olabilir, yanıttaki css dosyası da benim için çalışmıyor.
Maksim Vi.

3
Bu aynı zamanda onerrorolay kullanarak iyi bir çözümdür . stackoverflow.com/questions/30546795/…
Kimyasal Programcı

2
Başka bir etki alanından yüklenen CSS için çalışıyor mu? Hayır, harici stil sayfaları için .rules/ numaralandıramazsınız .cssRules. jsfiddle.net/E6yYN/13
Salman A

29

Sanırım soru, bir stil sayfasının yüklü olup olmadığını tespit etmek. Olası bir yaklaşım aşağıdaki gibidir:

1) CSS dosyanızın sonuna aşağıdaki gibi özel bir kural ekleyin:

#foo { display: none !important; }

2) İlgili div'i HTML'nize ekleyin:

<div id="foo"></div>

3) Belge hazır #fooolduğunda görünür olup olmadığını kontrol edin . Stil sayfası yüklendiyse görünmez.

Demo burada - jquery-ui pürüzsüzlük temasını yükler; stil sayfasına hiçbir kural eklenmez.


42
Akıllı bir çözüm için +1. Tek sorun, normalde birinin
CDN'sinde

2
Ne yazık ki, CDN dosyalarına kendi sınıflarımızı yazamıyoruz. Belki zaten var olanı kullanmaya çalışabiliriz.
Ahamed

1
Bunu çok beğendim, teşekkür ederim. Gerçekten oldukça güçlü. Açıkçası CDN stil sayfasını değiştiremem ama hangi sınıfların kullanıldığını biliyorum, bu yüzden kodu görünür olup olmadıklarını kontrol etmek için değiştirdim - gerçekten çok akıllıca :)
Nosnibor

3
Not: Harici CSS'ye gerçekten yeni bir kural eklemeniz gerekmez . Sadece davranışı bilinen mevcut bir kuralı kullanın. Demomda, öğeyi gizlemesi gereken ui-helper-hidden sınıfını kullanıyorum, ardından öğenin sayfa yüklenirken gizlenip gizlenmediğini kontrol ediyorum.
Salman A

28

Css ve jQuery için aynı CDN'yi kullandığınızı varsayarsak, neden sadece bir test yapıp hepsini yakalamıyorsunuz?

<link href="//ajax.googleapis.com/ajax/libs/jqueryui/1/themes/start/jquery-ui.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script type="text/javascript">
    if (typeof jQuery == 'undefined') {
        document.write(unescape('%3Clink rel="stylesheet" type="text/css" href="../../Content/jquery-ui-1.8.16.custom.css" /%3E'));
        document.write(unescape('%3Cscript type="text/javascript" src="/jQuery/jquery-1.6.4.min.js" %3E%3C/script%3E'));
        document.write(unescape('%3Cscript type="text/javascript" src="/jQuery/jquery-ui-1.8.16.custom.min.js" %3E%3C/script%3E'));
    }
</script>

1
Başlangıçta çıkış karaktersiz dizelerin kullanımıyla ilgili sorunun ne olduğunu sorabilir miyim, örneğin document.write("<script type='text/javascript' src='path/to/file.js'>")?
Jack Tuck

2
@JackTuck: ayrıştırıcı ayırt edemez <script>bir JS dize ve bulunduğunda dışarıdan içeriye. <\/script>CDN yedekleri için etiket yazarken de görmenizin nedeni budur .
Brad Christie

6
-1 why not just do one test and catch it all?- Çünkü birinin başarısız olması ve diğerlerinin başarılı olması için milyonlarca neden var.
Flimzy

7

bu makale bootstrap css için bazı çözümler önerir http://eddmann.com/posts/providing-local-js-and-css-resources-for-cdn-fallbacks/

alternatif olarak bu fontawesome için çalışır

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<script>
    (function($){
        var $span = $('<span class="fa" style="display:none"></span>').appendTo('body');
        if ($span.css('fontFamily') !== 'FontAwesome' ) {
            // Fallback Link
            $('head').append('<link href="https://stackoverflow.com/css/font-awesome.min.css" rel="stylesheet">');
        }
        $span.remove();
    })(jQuery);
</script>

Bunu Font Awesome 5 ile kullanmak isteyenler için, 'FontAwesome' (if cümlesinde) 'Font Awesome 5 Free' (ücretsiz yazı tiplerini kullanıyorsanız) olarak değiştirmek isteyeceksiniz. Aksi takdirde, iyi çalışması gerekir.
Jason Clark

4

Sen belki de stil varlığını sınamak mümkün document.styleSheets.

var rules = [];
if (document.styleSheets[1].cssRules)
    rules = document.styleSheets[i].cssRules
else if (document.styleSheets[i].rules)
    rule= document.styleSheets[i].rules

Kullandığınız CSS dosyasına özel bir şeyi test edin.


4

Bunun için kullanılabilir onerror:

<link rel="stylesheet" href="cdn.css" onerror="this.onerror=null;this.href='local.css';" />

this.onerror=null;Durumunda kendini kullanılamaz yedek özelliğini sonsuz döngüler kaçınmaktır. Ancak birden çok yedeğe sahip olmak için de kullanılabilir.

Ancak, bu şu anda yalnızca Firefox ve Chrome'da çalışmaktadır.


3

İşte Katy Lavallee'nin cevabının bir uzantısı. Değişken çarpışmaları önlemek için her şeyi kendi kendine çalışan işlev sözdizimine sardım. Ayrıca betiği tek bir bağlantıya özgü olmayan bir hale getirdim. IE, artık "data-fallback" url özniteliğine sahip tüm stil sayfası bağlantıları otomatik olarak ayrıştırılacaktır. Daha önce olduğu gibi bu betiğe url'leri sabit kodlamanız gerekmez. Bunun, <head>elemanın sonunda değil , elemanın sonunda yapılması gerektiğini unutmayın <body>, aksi takdirde FOUC'a neden olabilir .

http://jsfiddle.net/skibulk/jnfgyrLt/

<link rel="stylesheet" type="text/css" href="broken-link.css" data-fallback="broken-link2.css">

.

(function($){
    var links = {};

    $( "link[data-fallback]" ).each( function( index, link ) {
        links[link.href] = link;
    });

    $.each( document.styleSheets, function(index, sheet) {
        if(links[sheet.href]) {
            var rules = sheet.rules ? sheet.rules : sheet.cssRules;
            if (rules.length == 0) {
                link = $(links[sheet.href]);
                link.attr( 'href', link.attr("data-fallback") );
            }
        }
    });
})(jQuery);

1
Kapsüllemeyi seviyorum, ancak genel olarak, domainler arası bir stil sayfası için sheet.rules'ı inceleyemezsiniz. Yine de bu genel fikri kullanabilirsiniz, ancak farklı bir kontrol yapmanız gerekir.
John Vinopal

ile özniteliklere document.styleSheets[i].ownerNode.dataseterişebilirsiniz<link data-* />
Alwin Kesler

2

Bir CDN'nin başarısız olması durumunda CSS'yi yüklemek için bu javascript rotasına gerçekten girmek istiyor musunuz?

Tüm performans etkilerini düşünmedim, ancak CSS'nin ne zaman yüklendiğinin kontrolünü kaybedeceksiniz ve genel olarak sayfa yükleme performansı için, CSS, HTML'den sonra indirmek istediğiniz ilk şeydir.

Bunu neden altyapı düzeyinde ele almıyorsunuz - kendi alan adınızı CDN ile eşleştirin, ona kısa bir TTL verin, CDN'deki dosyaları izleyin (örn. Watchmouse veya başka bir şey kullanarak), CDN başarısız olursa, DNS'yi yedekleme sitesi olarak değiştirin.

Yardımcı olabilecek diğer seçenekler statik içerik üzerinde "sonsuza kadar önbellekleme" dir ancak tarayıcının bunları elbette tutacağının veya uygulama önbelleğini kullanacağının garantisi yoktur.

Gerçekte, en tepede birinin söylediği gibi, CDN'niz güvenilmezse yeni bir tane alın

Andy


7
CDN güvenilir olabilir, ancak geliştirme ortamı internet bağlantısı değil;)
icebreaker

1

Şu işlevlere bakın:

$.ajax({
    url:'CSS URL HERE',
    type:'HEAD',
    error: function()
    {
        AddLocalCss();
    },
    success: function()
    {
        //file exists
    }
});

Ve işte vanilya JavaScript sürümü:

function UrlExists(url)
{
    var http = new XMLHttpRequest();
    http.open('HEAD', url, false);
    http.send();
    return http.status!=404;
}
if (!UrlExists('CSS URL HERE') {
AddLocalCss();
}

Şimdi asıl işlev:

function AddLocalCss(){
document.write('<link rel="stylesheet" type="text/css" href=" LOCAL CSS URL HERE">')
}

Sadece AddLocalCss'ın baştan çağrıldığından emin olun.

Bu yanıtta açıklanan aşağıdaki yollardan birini kullanmayı da düşünebilirsiniz :

AJAX kullanarak yükleyin

$.get(myStylesLocation, function(css)
{
   $('<style type="text/css"></style>')
      .html(css)
      .appendTo("head");
});

Dinamik olarak oluşturulmuş kullanarak yükleyin

$('<link rel="stylesheet" type="text/css" href="'+myStylesLocation+'" >')
   .appendTo("head");
Load using dynamically-created <style>

$('<style type="text/css"></style>')
    .html('@import url("' + myStylesLocation + '")')
    .appendTo("head");

veya

$('<style type="text/css">@import url("' + myStylesLocation + '")</style>')
    .appendTo("head");

Evet, en azından modern tarayıcıda IE6'dan emin değilim.

Her şeyi indirmek yerine kontrol etmenin bir yolu var mı?
Shawn Mclean

OP'lerin talebini yapmanın tek olası nedeni aşırı ağ trafiğinden kaçınmaktır. Bu, aşırı ağ trafiği yaratır.
Stefan Kendall

@stefan Kendall: Hayır, dosyaların yüklendiğinden emin olmak istemesinin olası nedeni bile değil.

Tek endişe bu olsaydı, bir CDN kullanmazdın. Yalnızca başlığı test etmek daha iyidir, ancak çoğu CDN'nin ve tarayıcınızın XSS'ye izin vermeyeceğinden eminim.
Stefan Kendall

-1

Muhtemelen yepnope.js gibi bir şey kullanırdım

yepnope([{
  load: 'http:/­/ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js',
  complete: function () {
    if (!window.jQuery) {
      yepnope('local/jquery.min.js');
    }
  }
}]);

Benioku dosyasından alınmıştır .


10
@BenSchwarz, bu, sorulan soruyu hiçbir şekilde yanıtlamayan bazı alakasız kodları yapıştırabileceğiniz anlamına gelmez.
AlicanC

-8
//(load your cdn lib here first)

<script>window.jQuery || document.write("<script src='//me.com/path/jquery-1.x.min.js'>\x3C/script>")</script>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.