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:

JavaScript:
  1. $(document).ready(function(){
  2. var container = $('#target');
  3. $('.ajaxtrigger').click(function(){
  4. doAjax($(this).attr('href'));
  5. return false;
  6. });
  7. function doAjax(url){
  8. // if it is an external URI
  9. if(url.match('^http')){
  10. // call YQL
  11. $.getJSON("http://query.yahooapis.com/v1/public/yql?"+
  12. "q=select%20*%20from%20html%20where%20url%3D%22"+
  13. encodeURIComponent(url)+
  14. "%22&format=xml'&callback=?",
  15. // this function gets the data from the successful
  16. // JSON-P call
  17. function(data){
  18. // if there is data, filter it and render it out
  19. if(data.results[0]){
  20. var data = filterData(data.results[0]);
  21. container.html(data);
  22. // otherwise tell the world that something went wrong
  23. } else {
  24. var errormsg = '<p>Error: could not load the page.</p>';
  25. container.html(errormsg);
  26. }
  27. }
  28. );
  29. // if it is not an external URI, use Ajax load()
  30. } else {
  31. $('#target').load(url);
  32. }
  33. }
  34. // filter out some nasties
  35. function filterData(data){
  36. data = data.replace(/<?/body[^>]*>/g,'');
  37. data = data.replace(/[r|n]+/g,'');
  38. data = data.replace(/<--[Ss]*?-->/g,'');
  39. data = data.replace(/<noscript[^>]*>[Ss]*?</noscript>/g,'');
  40. data = data.replace(/<script[^>]*>[Ss]*?</script>/g,'');
  41. data = data.replace(/<script.*/>/,'');
  42. return data;
  43. }
  44. });

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):

JavaScript:
  1. $('#container').load('http://google.com'); // SERIOUSLY!
  2.  
  3. $.ajax({
  4.     url: 'http://news.bbc.co.uk',
  5.     type: 'GET',
  6.     success: function(res) {
  7.         var headline = $(res.responseText).find('a.tsh').text();
  8.         alert(headline);
  9.     }
  10. });

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!


RAM dysk

16 września 2010

Kupując komputer wiele osób daje się omamić magią liczb i zwracają uwagę tylko na cyferki serwowane im przez sprytnych marketingowców. Ci trochę bardziej świadomi przed podjęciem decyzji czytają opinie innych, testy kart graficznych, procesorów, czasami płyt głównych. Osobiście mam jednak wrażenie, że jednym z najmniej absorbujących uwagę klientów elementem komputera są twarde dyski. Przeważnie każdy skupia się jedynie na pojemności i przechodzi do następnego punktu na liście zakupów. Błąd.

Dysk twardy to szalenie ważny wybór. Można wybrać najwydajniejszą kartę graficzną i najszybszy procesor a komputer i tak będzie wolno działał jeżeli zaoszczędzimy na napędzie HDD. Temat jest bardzo obszerny, od prędkości obrotowych talerzy poprzez dyski SSD aż po macierze RAID. Dobrze przemyślana inwestycja w "twardziele" procentuje!

Są jednak takie zadania gdzie wydajność dysków twardych ma decydujące znaczenie. Czy istnieje jakiś sposób drastycznego zwiększenia ich wydajności? Nie, nie istnieje. Ale można stworzyć RAM dysk.

Pamięci RAM są piekielnie szybkie, wielokrotnie szybsze od jakiegokolwiek napędu, dysku twardego etc. Niestety jest to pamięć ulotna, po odcięciu zasilania dane przepadają. Jest jednak sposób aby użyć swojej pamięci RAM jako zwykłego dysku twardego. Istnieją programy, które potrafią wmówić Waszemu systemowi operacyjnemu, że część Waszego RAM'u to dysk twardy. Po instalacji i konfiguracji pojawia się po prostu nowa literka na liście dysków/partycji. Można tam tworzyć/usuwać foldery, kopiować pliki, robić wszystko to co robimy na co dzień ze swoimi napędami HDD.

Słowem kluczem jest "szybkość". Posiadam dwa wydajne dyski twarde, połączyłem je w macierz RAID 0. To rozwiązanie daje naprawdę bardzo dobre wyniki, transfer danych jest dużo lepszy niż przy zwykłych dyskach i/lub bez RAID. Jednak po instalacji dysku RAM... Dokładne testy wymagałyby godzin pracy, wszystko zależy od odpowiedniej konfiguracji, wielkości danych na jakich pracujemy, systemu plików na dysku itd. Ale zwykły test jednym z wielu programów do sprawdzania wydajności dysków twardych wykazał, że transfery wzrosły od kilkunastu do nawet kilkuset razy, zależnie czy to zapis czy odczyt oraz od wielkości danych. Imponujące.

Tyle o zaletach. Teraz wady :) Przede wszystkim dane z takiego dysku znikają. Gdy używamy go tylko chwilowo do przyspieszenia działania jakiegoś programu to raczej nie ma to dla nas większego znaczenia. Może być to nawet zaleta np. ustawiając zmienne środowiskowe systemu tak aby na naszym dysku RAM był systemowy katalog Temp, który będzie czyścił się automatycznie przy każdym wyłączeniu komputera :)

Programy umożliwiające tworzenie dysków RAM pozwalają na "obejście" problemu znikania danych. Przy zamykaniu systemu tworzą obraz naszego dysku a przy starcie wczytują go na nowo. Niestety ma to kilka wad. Zapis i odczyt odbywa się na naszym zwykłym dysku twardym a to niestety trwa. Przy większych dyskach całkiem długo. Poza tym gdy z jakiegoś powodu praca naszego systemu zostanie nagle przerwana i nie dojdzie do zapisu obrazu to po ponownym włączeniu komputera dostaniemy starsze pliki. Te, które powstały od momentu ostatniego zapisu obrazu przepadną na zawsze. W programie o którym napiszę na końcu jest auto zapis, obraz aktualizuje się co wybraną ilość sekund. Spadnie jednak wtedy wydajność naszych normalnych dysków co może negatywnie wpłynąć na pracę całego systemu. Na końcu trzeba wspomnieć, że obraz może ulec uszkodzeniu (auto zapis zwiększa to niebezpieczeństwo) i wszystko nam przepadnie.

Innym minusem jest fakt, że użyta w ten sposób pamięć RAM z oczywistych względów nie może być używana przez system. Dlatego na RAM dysk mogą sobie pozwolić tylko osoby z nadwyżką tej pamięci. Nie ma sensu robić RAM dysku gdy w konsekwencji dla systemu zabraknie RAM'u i system zostanie zmuszony korzystać z pliku wymiany. Więcej strat z takiego rozwiązania niż pożytku.

Do czego taki dysk może nam posłużyć? Ułatwi życie przede wszystkim tam gdzie potrzeba wiele operacji odczytu/zapisu danych, zwłaszcza małych plików. Można sobie np. ustawić tak system, o czym wspomniałem wyżej, aby nasz dysk był używany do przechowywania plików tymczasowych zamiast standardowych katalogów Temp. Jednak i tu trzeba uważać. Gdy nie użyjemy obrazu i przy każdym starcie systemu nasz dysk będzie pusty to takie programy jak np. Internet Explorer, który używa systemowych katalogów tymczasowych aby trzymać tam pliki cache, straci na wydajności. Nie wiem jak jest z IE ale np. Firefox pozwala ustawić własny, niezależny od ustawień systemu, folder plików tymczasowych. Polecam go nie przestawiać na nasz dysk RAM.

To tylko jeden przykład z wielu użyteczności rozwiązania jakim jest RAM dysk. Prace z bazami danych, przetwarzanie grafiki, audio, wideo. Pomysły można mnożyć. Każdy sam musi zdecydować czy takiego dysku potrzebuje i jak go wykorzystać. Odradzałbym raczej hura optymizm i np. instalowanie na takim dysku programów bo wtedy trzeba włączyć używanie obrazu a oczekiwanie na jego odczyt/zapis potrafi zniechęcić. Z drugiej strony warto mieć pół czy jeden giga takiego "ekstra" dysku pod ręką jeżeli raz na jakiś czas wykonujemy czynności, które normalnie wyciskają siódme poty z naszych biednych "twardzieli". Wybór należy do Ciebie, kieruj się logiką i oceń bilans plusów oraz minusów.

Przez długi czas używałem takiego dysku o wielkości 1 GB z użyciem obrazu. W końcu jednak oczekiwanie na odczyt/zapis przy starcie/zamykaniu systemu zaczął mi na tyle doskwierać, że postanowiłem zmienić ustawienia. Jak na zawołanie, z jakiegoś powodu uszkodzeniu uległ używany obraz (nie było tam nic wartościowego) co zmobilizowało mnie wreszcie do działania ;) Teraz mam dysk RAM ale bez zapisywania jego zawartości, jedynie do bieżącego użytku, plików tymczasowych itp. Zobaczymy jak takie rozwiązanie będzie się spisywało.

Na koniec dwie sprawy wymagające wyjaśnienia. Po pierwsze, ReadyBoost. Technologia po raz pierwszy wprowadzona w Windows Vista (z tego co wiem to były podobne rozwiązania firm zewnętrznych dla Windows XP), która pozwala używać szybkich napędów np. pamięci FLASH do przyspieszenia systemu. Nasz dysk RAM zostanie przetestowany i system uzna, że nadaje się on do wykorzystania dla tej technologii jednak NIE korzystajcie z tej funkcji. ReadyBoost, owszem, jest przydatne ale tam gdzie wielkość pamięci RAM jest niewystarczająca. Wtedy użycie np. PenDrive z tą funkcją pozwoli trochę przyspieszyć działanie systemu jako iż pamięci FLASH są szybsze od zwykłych, talerzowych dysków twardych. W naszym przypadku nie ma to jednak sensu... Lepiej żeby system miał do dyspozycji więcej RAM'u niż mielibyśmy mu go zabrać po czym ponownie oddać w postaci RAM dysku, tylko poprzez "pośredników" co oczywiście zmniejszy wydajność.

Druga sprawa to "znikający" RAM. Pewne ograniczenia powodują, że 32-bitowe systemy (na pewno Windows XP, od Visty włącznie podobno problem został rozwiązany ale wiem na pewno, że Vista czasami nadal sobie nie radzi) nie potrafią obsłużyć więcej niż 4GB RAM'u. Jeżeli masz więcej, marnuje się on. Oczywiście najlepiej zainstalować nowszy system lub jakąś łatkę/64-bitową wersję ale jeżeli dobrze Ci tak jak jest to Twoja nieużywana część RAM'u idealnie nadaje się na RAM dysk :) To również jedyny wyjątek gdy włączenie ReadyBoost ma jakiś sens. System i tak z tego RAM'u nie potrafi korzystać. Inna sprawa, że ReadyBoost pewnie się nie przyda skoro system ma do dyspozycji 4 GB RAM'u :)

Programów do tworzenia RAM dysków jest sporo. Przetestowałem kilka i najlepiej radził sobie u mnie Dataram RAMDisk (bezpłatny dla dysków do 4 GB, za większe trzeba zapłacić 10$). Z innymi były różne problemy, niektóre zupełnie nie działały, inne były niestabilne. Ten przez wiele miesięcy nie sprawił mi żadnego problemu (aż do uszkodzenia pliku obrazu ale to raczej nie jego wina). Ma funkcje obsługi obrazu, auto zapis, automatyczne tworzenie katalogu Temp czy wykorzystanie pamięci RAM, której nasz system nie widzi. Polecam. Warto też przeczytać krótką dokumentację chociaż instalacja/deinstalacja zarówno programu jak i samego dysku RAM a także konfiguracja wszystkiego są bardzo proste.

Program pozwala stworzyć dysk z systemami plików FAT 16, FAT 32 lub niesformatowane (samemu można potworzyć partycje). Nie ma NTFS bo Microsoft nie udostępnił pełnej dokumentacji tego systemu. Mimo to można użyć wbudowanych w system narzędzi i sformatować dysk jak się chce. Aby jednak zmiany zostały zachowane, należy włączyć używanie obrazu. W innym przypadku po ponownym starcie systemu system plików zostanie "zresetowany" do ustawień jakie zaznaczymy w programie. Jeżeli nie używasz obrazu to, moim zdaniem, najlepiej ustawić FAT 32.


Flash z obcej domeny

09 sierpnia 2010

Gdy próbujemy osadzić na naszej stronie plik flash pochodzący z innej domeny możemy spotkać się z problemem braku interakcji. Nagle przestają działać np. odnośniki.

Jest na to rozwiązanie. Podczas osadzania pliku SWF należy umieścić dodatkowy parametr: AllowScriptAccess. Może on przyjmować trzy ustawienia:

  • always - komunikacja między plikiem Flash a stroną www na której plik został umieszczony odbywa się zawsze, nawet gdy plik jest umieszczony pod innym adresem niż sama strona.
  • sameDomain - komunikacja następuje tylko gdy strona i plik znajdują się w tej samej domenie.
  • never - niezalecane i wycofywane ustawienie. Komunikacja nie następuje nigdy. Dokumentacja proponuje, że jeżeli masz pliki SWF, którym nie ufasz i nie chcesz aby mogły się komunikować to utwórz dla nich osobną subdomenę i stamtąd je linkuj ustawiając AllowScriptAccess na "sameDomain".

Domyślne ustawienie parametru AllowScriptAccess to sameDomain. Pamiętaj o tym! Przy takim ustawieniu napotkasz problemy wstawiając SWF z innej domeny.

PS
Problem może dotyczyć nawet sytuacji gdy wejdziemy na stronę poprzez adres z www a pliki flash wstawione są jako adresy bez www. Najłatwiejszym rozwiązaniem problemu jest użyć przekierowanie 301. Tylko pamiętajcie, że jeżeli macie przekierowanie to mimo to starajcie się podawać prawidłowe adresy. Po co męczyć serwer dodatkowymi przekierowaniami...

PS 2
Wpis inspirowany moimi wczorajszymi problemami :)


Odczytanie sesji mając tylko jej ID

19 sierpnia 2009

Dzisiaj stanąłem przed pewnym problemem, który powstał w takiej sytuacji:
- mam panel administracyjny dostępny po zalogowaniu
- informacja o zalogowanym użytkowniku trzymana jest w sesji
- ID sesji jest przekazywany wyłącznie za pomocą cookie
- potrzebuję komunikować się między PHP a Flash

Problem powstał właśnie w miejscu komunikacji między PHP i Flash. Z jakiegoś powodu plik PHP wywoływany przez Flash nie potrafił odczytać sesji, tworzył nową. A ja musiałem odczytać info z sesji czy użytkownik jest zalogowany i ma odpowiednie uprawnienia. Ten element strony odpowiada za wgrywanie zdjęć na serwer i nie mógłbym zostawić tak dużej dziury w bezpieczeństwie.

Osobiście byłem tym problemem mocno zaskoczony bo przecież ID sesji przekazywane jest w cookie i PHP nie powinno mieć żadnego problemu z odczytaniem tej wartości. W jakiś sposób przeszkadza tu Flash bo inne skrypty oparte na Ajax działają bez problemów. Niestety na budowę Flash nie mam wpływu, korzystam z gotowego rozwiązania. Gdzieś tutaj widziałem źródła Flash ale nie po to stosuję gotowca żeby teraz w nim grzebać i pamiętać o zmianach zawsze gdy będę przeprowadzał aktualizację. Czytaj dalej »