Połączenie AJAX z obcą domeną za pomocą jQuery
22 października 2011
AJAX to wspaniała technologia dzięki której mogło powstać wiele rewolucyjnych usług. Ma ona jednak pewne ograniczenia związane z polityką bezpieczeństwa przeglądarek. Jednym z największych ograniczeń jest możliwość łączenia się poprzez AJAX wyłącznie ze stronami w tej samej domenie. Krótko mówiąc, nie ma możliwości pobrać strony example2.com ze strony example1.com. Tak przynajmniej myślałem do tej pory
Nim jeszcze przejdę do meritum sprawy, dodam, że oczywiście istnieje obejście problemu. Można napisać swego rodzaju proxy w PHP lub w innym języku i za pomocą tego proxy pobierać docelową stronę. Trzeba jednak koniecznie pamiętać aby przy tego typu rozwiązaniach jakoś filtrować kto korzysta z naszego skryptu i co pobiera. Inaczej będą problemy bo skrypt musi być przecież publicznie dostępny.
Nam jednak zależy aby całą sprawę załatwić z poziomu JavaScript. Z pomocą przychodzi YQL od Yahoo!.
Czym jest YQL? W dużym uproszczeniu, jest to język składniowo podobny do SQL, który pozwala na odczyt/manipulację różnymi zorganizowanymi strukturami danych np. HTML. Jego możliwości możemy wykorzystać dla własnych celów o czym możemy się dowiedzieć z tego artykułu. Pozwolę sobie skopiować jeden przykład:
-
$(document).ready(function(){
-
var container = $('#target');
-
$('.ajaxtrigger').click(function(){
-
doAjax($(this).attr('href'));
-
return false;
-
});
-
function doAjax(url){
-
// if it is an external URI
-
if(url.match('^http')){
-
// call YQL
-
$.getJSON("http://query.yahooapis.com/v1/public/yql?"+
-
"q=select%20*%20from%20html%20where%20url%3D%22"+
-
encodeURIComponent(url)+
-
"%22&format=xml'&callback=?",
-
// this function gets the data from the successful
-
// JSON-P call
-
function(data){
-
// if there is data, filter it and render it out
-
if(data.results[0]){
-
var data = filterData(data.results[0]);
-
container.html(data);
-
// otherwise tell the world that something went wrong
-
} else {
-
var errormsg = '<p>Error: could not load the page.</p>';
-
container.html(errormsg);
-
}
-
}
-
);
-
// if it is not an external URI, use Ajax load()
-
} else {
-
$('#target').load(url);
-
}
-
}
-
// filter out some nasties
-
function filterData(data){
-
data = data.replace(/<?/body[^>]*>/g,'');
-
data = data.replace(/[r|n]+/g,'');
-
data = data.replace(/<--[Ss]*?-->/g,'');
-
data = data.replace(/<noscript[^>]*>[Ss]*?</noscript>/g,'');
-
data = data.replace(/<script[^>]*>[Ss]*?</script>/g,'');
-
data = data.replace(/<script.*/>/,'');
-
return data;
-
}
-
});
To kompleksowy kod, który pozwala stworzyć proste odnośniki na stronie służące do pobierania zewnętrznych witryn, przy okazji filtrując wyniki z potencjalnie niebezpiecznego kodu. Dobrze wiedzieć, że YQL pobiera tylko zawartość tagu body docelowej strony, co ma oczywiście swoje konsekwencje np. dostaniemy dostęp tylko do tych styli CSS, które zostały bezpośrednio "wpisane" w tagi HTML, tzw. inline CSS.
Pod tym adresem znajduje się prezentacja działania tego kodu.
Na github.com znajduje się również prosty skrypt jQuery, który szalenie upraszcza korzystanie z dobrodziejstw YQL. Dzięki niemu możemy korzystać z dotychczasowych rozwiązań opartych o AJAX i podawać zewnętrzne adresy www a skrypt sam martwi się już o to aby cały proces przebiegł bez problemów. Przykład użycia (z tej strony):
-
$('#container').load('http://google.com'); // SERIOUSLY!
-
-
$.ajax({
-
url: 'http://news.bbc.co.uk',
-
type: 'GET',
-
success: function(res) {
-
var headline = $(res.responseText).find('a.tsh').text();
-
alert(headline);
-
}
-
});
Warto wspomnieć o alternatywnej metodzie. Istnieją rozwiązania w których JS łączy się z odpowiednim plikiem Flash i to on wykonuje za nas robotę polegającą na pobraniu zawartości strony. Ograniczeniem tej metody jest fakt, że komunikacja nie może być zablokowana na domenie docelowej w pliku crossdomain.xml. Popularnym skryptem rozwiązującym problem właśnie za pomocą Flash'a jest flXHR.
Kłopot z tzw. cross-domain AJAX jest obszerny, mam za małą wiedzę aby móc go lepiej opisać. Żywię jednak nadzieję, że tekst będzie przydanty i pomoże komuś rozwiązać jego problemy. Zachęcam do samodzielnego zgłębiania problemu i dzielenia się wiedzą w komentarzach.
PS
Pytanie za 100 punktów. Skoro AJAX nie pozwala pobierać danych z zewnętrznych adresów www to jakim cudem pozwala łączyć się z domeną http://query.yahooapis.com/ ? Pytam szczerze bo ja tego nie wiem
Firebug nie pokazuje ruchu generowanego za pomocą tego rozwiązania jako ruch AJAX tylko przypisuje go do zakładki JS.
EDIT
Czytaj komentarze, koledzy dali tam wiele interesujących, uzupełniających informacji!
Blog przede wszystkim o Internecie i mojej pasji jaką jest tworzenie stron www. Ale nie ograniczam się do jednej tematyki, piszę o wszystkim o czym mam ochotę :-)