Ajax mezi doménami se sdílením zdrojů mezi zdroji

Před pár lety weboví vývojáři mlátili hlavou o první zeď v Ajaxu:politiku stejného původu. Zatímco jsme žasli nad obrovským krokem vpřed, který umožnila podpora napříč prohlížeči pro XMLHttpRequest objekt, rychle jsme si naříkali, že neexistuje způsob, jak provést požadavek na jinou doménu než JavaScript. Každý si na svých webových stránkách nastavil proxy, což byl počátek nových problémů s otevřeným přesměrováním, jako způsob, jak obejít omezení. Přestože vývojáři toto omezení obcházeli pomocí serverových proxy serverů a dalších technik, komunita se rozhořčila kolem povolení nativních požadavků Ajaxu napříč doménami. Mnoho lidí si neuvědomuje, že téměř všechny prohlížeče (Internet Explorer 8+, Firefox 3.5+, Safari 4+ a Chrome) v současnosti podporují Ajax mezi doménami prostřednictvím protokolu zvaného Cross-Origin Resource Sharing.

Cross-Origin Resource Sharing (CORS)

Cross-Origin Resource Sharing (CORS) je pracovní návrh W3C, který definuje, jak musí prohlížeč a server komunikovat při přístupu ke zdrojům z různých zdrojů. Základní myšlenkou CORS je použití vlastních HTTP hlaviček, které umožní jak prohlížeči, tak serveru o sobě navzájem vědět dost, aby bylo možné určit, zda má požadavek nebo odpověď uspět nebo selhat.

Pro jednoduchý požadavek, který používá buď GET nebo POST bez vlastních záhlaví a jehož tělo je text/plain , je požadavek odeslán s extra hlavičkou nazvanou Origin . Origin hlavička obsahuje původ (protokol, název domény a port) žádající stránky, takže server může snadno určit, zda má či nemá poskytnout odpověď. Příklad Origin záhlaví může vypadat takto:

Origin: https://humanwhocodes.com

Pokud server rozhodne, že by měl být požadavek povolen, odešle Access-Control-Allow-Origin záhlaví odrážející stejný původ, který byl odeslán, nebo „*“, pokud se jedná o veřejný zdroj. Například:

Access-Control-Allow-Origin: https://humanwhocodes.com

Pokud toto záhlaví chybí nebo se zdroje neshodují, prohlížeč požadavek zakáže. Pokud je vše v pořádku, prohlížeč požadavek zpracuje. Upozorňujeme, že požadavky ani odpovědi neobsahují informace o souborech cookie.

Všechny výše uvedené prohlížeče podporují tyto jednoduché požadavky. Firefox 3.5+, Safari 4+ a Chrome všechny podporují použití prostřednictvím XMLHttpRequest objekt. Při pokusu o otevření prostředku v jiném zdroji se toto chování automaticky spustí bez dalšího kódu. Například:

var xhr = new XMLHttpRequest();
xhr.open("get", "https://humanwhocodes.com/some_resource/", true);
xhr.onload = function(){  //instead of onreadystatechange
    //do something
};
xhr.send(null);

Chcete-li provést totéž v aplikaci Internet Explorer 8, budete muset použít XDomainRequest objekt stejným způsobem:

var xdr = new XDomainRequest();
xdr.open("get", "https://humanwhocodes.com/some_resource/");
xdr.onload = function(){
    //do something
};
xdr.send();

Tým Mozilly ve svém příspěvku o CORS navrhuje, že byste měli zkontrolovat existenci withCredentials vlastnost k určení, zda prohlížeč podporuje CORS přes XHR. Poté můžete spojit s existencí XDomainRequest objekt pro pokrytí všech prohlížečů:

function createCORSRequest(method, url){
    var xhr = new XMLHttpRequest();
    if ("withCredentials" in xhr){
        xhr.open(method, url, true);
    } else if (typeof XDomainRequest != "undefined"){
        xhr = new XDomainRequest();
        xhr.open(method, url);
    } else {
        xhr = null;
    }
    return xhr;
}

var request = createCORSRequest("get", "https://humanwhocodes.com/");
if (request){
    request.onload = function(){
        //do something with request.responseText
    };
    request.send();
}

XMLHttpRequest objekt ve Firefoxu, Safari a Chrome má dostatečně podobná rozhraní jako IE XDomainRequest že tento vzor funguje docela dobře. Společné vlastnosti/metody rozhraní jsou:

  • abort() – použijte k zastavení požadavku, který již probíhá.
  • onerror – použijte místo onreadystatechange k odhalení chyb.
  • onload – použijte místo onreadystatechange k odhalení úspěchů.
  • responseText – použijte k získání obsahu odpovědi.
  • send() – použijte k odeslání požadavku.

Předběžné požadavky

CORS umožňuje použití vlastních hlaviček, metod jiných než GET nebo POST a různých typů obsahu těla prostřednictvím transparentního mechanismu ověřování serveru nazývaného požadavky před výstupem. Když se pokusíte vytvořit požadavek pomocí jedné z pokročilých možností, bude serveru odeslán požadavek „před výstupem“. Tento požadavek používá metodu OPTIONS a odesílá následující hlavičky:

  • Origin – stejně jako v jednoduchých žádostech.
  • Access-Control-Request-Method – metoda, kterou chce požadavek použít.
  • Access-Control-Request-Headers – (Volitelné) čárkami oddělený seznam používaných vlastních záhlaví.

Příklad předpokládá požadavek POST s vlastní hlavičkou nazvanou NCZ :

Origin: https://humanwhocodes.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: NCZ

Během tohoto požadavku může server určit, zda povolí nebo nepovolí požadavky tohoto typu. Server to sdělí prohlížeči odesláním následujících hlaviček v odpovědi:

  • Access-Control-Allow-Origin – stejně jako v jednoduchých žádostech.
  • Access-Control-Allow-Methods – čárkami oddělený seznam povolených metod.
  • Access-Control-Allow-Headers – čárkami oddělený seznam záhlaví, které server povolí.
  • Access-Control-Max-Age – množství času v sekundách, po které by měl být tento požadavek před výstupem uložen do mezipaměti.

Příklad:

Access-Control-Allow-Origin: https://humanwhocodes.com
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 1728000

Jakmile byl proveden požadavek na kontrolu před výstupem, výsledek se uloží do mezipaměti po dobu uvedenou v odpovědi; náklady na další požadavek HTTP vám vzniknou pouze při prvním odeslání požadavku tohoto typu.

Firefox 3.5+, Safari 4+ a Chrome všechny podporují požadavky před výstupem; Internet Explorer 8 ne.

Žádosti o pověření

Ve výchozím nastavení neposkytují požadavky napříč původem přihlašovací údaje (soubory cookie, ověřování HTTP a certifikáty SSL na straně klienta). Nastavením withCredentials můžete určit, že má požadavek odeslat přihlašovací údaje vlastnost na pravdu. Pokud server povolí pověřené požadavky, odpoví následující hlavičkou HTTP:

Access-Control-Allow-Credentials: true

Pokud je odeslán požadavek s pověřením a toto záhlaví není odesláno jako součást odpovědi, prohlížeč nepředá odpověď JavaScriptu (responseText je prázdný řetězec, status je 0 a onerror() je vyvoláno). Všimněte si, že server může také odeslat tuto HTTP hlavičku jako součást preflightové odpovědi, aby indikoval, že zdroj může odesílat pověřené požadavky.

Internet Explorer 8 nepodporuje withCredentials vlastnictví; Firefox 3.5, Safari 4 a Chrome to všechny podporují.

Závěr

V moderních webových prohlížečích existuje spousty solidní podpory pro Ajax napříč doménami, ale většina vývojářů o této výkonné schopnosti stále neví. Použití vyžaduje jen trochu práce JavaScriptu navíc a trochu práce navíc na straně serveru, aby bylo zajištěno, že jsou odesílána správná záhlaví. Implementace IE8 trochu zaostává za ostatními, pokud jde o povolení pokročilých požadavků a požadavků s pověřením, ale doufejme, že podpora pro CORS se bude nadále zlepšovat. Pokud se chcete dozvědět více, vřele doporučuji podívat se na stránku s příklady Aruna Ranganathana.

Aktualizace (25. května 2010): Opraven překlep v ukázkovém kódu.

Aktualizace (27. května 2010): Odstraněno koncové lomítko ze záhlaví Origin.