8 августа 2011 г.

Кросдоменный ajax с помощью javascript


В прошлом посте был описан способ передачи данных на сервер с помощью тега img на странице. Но он не единственный способ.
Для этих целей можно приспособить тег script, котороый так же будет передовать данные на сервер и еще асинхронно передавать ответ обратно.
html код:
Copy Source | Copy HTML
  1. <input type="text" id="textField"/>
  2. <input type="button" id="sendMessage" value="Отправить IMG"/>
  3. <img id="imaGet" src="picture.php?add=hello" style="width:30px;height:30px;"/>
javascript код:
Copy Source | Copy HTML
  1. function ScriptDataSend(urlEncoded_str,callBack_func){
  2.     ////generate uniq id for elements (I don't check it, only random!!)
  3.     var uniqId=(Math.random()*10000000).toFixed( 0);
  4.     //console.log("uniq: %s",uniqId);
  5.     ////add script element and encoded data
  6.     var th = document.getElementsByTagName("body")[ 0];
  7.     var s = document.createElement('script');
  8.     s.setAttribute('type','text/javascript');
  9.     s.setAttribute('src',"script.php?uid="+uniqId+"&add="+urlEncoded_str);
  10.  
  11.     s.setAttribute('id',uniqId);
  12.     ////auto remove script element
  13.     s.onload=function(){
  14.         //console.log("I'm loaded");
  15.         s.parentNode.removeChild(s);
  16.         delete window.responceCollection[uniqId];
  17.     }
  18.     th.appendChild(s);
  19.     delete s;
  20.     //// add callback in globalScope!
  21.     if (window.responceCollection==undefined)
  22.         window.responceCollection={};
  23.     window.responceCollection[uniqId]=callBack_func;
  24. }
  25.  
  26. var messageField=document.getElementById("textField");
  27. var sendButton2=document.getElementById("sendMessage2");
  28. sendButton2.addEventListener("click",function(){
  29.         ScriptDataSend(encodeURIComponent(messageField.value),function(time){
  30.             console.log("Get Javascript response: %s",time);
  31.         });
  32.     },false);
Функция ScriptDataSend создает тег script с заранее определенным url адресом и уникальным id (uid),  чтобы используя этот uid задать уникальный обработчик события для этого соединения в глобальном хэше обработчиков window.responceCollection (другого "красивого" варианта реализации пока не придумал ...).
код файла script.php:
Copy Source | Copy HTML
  1. <?php
  2. header('Content-type: text/javascript');//Делаем вид что javascript
  3. $time=date("H:i:s");
  4. $uid=$_GET["uid"];
  5. // отправляем ответ
  6. echo "window.responceCollection[\"".$uid."\"]('".$time."');";
  7. //- сохраняем полученные данные
  8. $fileName="script_data.txt";
  9. if (strlen($_GET["add"])> 0){
  10.     $fh = fopen($fileName, "a+");
  11.     fwrite($fh, urldecode($_GET["add"])." ".date("H:i:s")."\n");
  12.     fclose($fh);
  13. }
  14. ?>
Как видите, script.php формирует ответ в виде набора данных и передает их в обработчик с уникальным id (uid).
Повозможности никакого управляющего кода на js в php скрипте не генирируется, чтобы было удобнее отлаживать.

Недостатки метода отправки данных сервер с помощью тега script:

  1. только запросы get
  2. вся отладка на плечи кодера
  3. добавление и удаление элемента из DOM
  4. обработчик в глобальной области видимости 

Кросдоменный ajax с помощью тега IMG

С помощью тега img можно отправить данные на сервер. Таким же образом действует и счетчик Яндекс Метрики, когда отправляет данные о кликах посетителей на страницах сайтов.
Создавать фейковую картинку 1px x 1px необязательно, картинка может быть обычной и может служить элементом декора на странице.
И при этом, главное, что, может передавать данные на сервер.
html код:
Copy Source | Copy HTML
  1. <input type="text" id="textField"/>
  2. <input type="button" id="sendMessage" value="Отправить IMG"/>
  3. <img id="imaGet" src="picture.php?add=hello" style="width:30px;height:30px;"/>
javascript код:
Copy Source | Copy HTML
  1. var messageField=document.getElementById("textField");
  2. var sendButton=document.getElementById("sendMessage");
  3. var imageElement=document.getElementById("imaGet");
  4. //Отправка данных на сервер методом get:
  5. sendButton.addEventListener("click",function(){
  6.     //определяем куда в аддресс вставлять сообщение по позиции фрагмента:
  7.     var pos= imageElement.src.indexOf("add=");
  8.     var newLink= imageElement.src.substring( 0,pos)+"add="+encodeURIComponent(messageField.value);
  9.     imageElement.src=newLink;//Присваиваем новый адресс - пофакту отправляем сообщение на сервер
  10. },false);
код файла picture.php:
Copy Source | Copy HTML
  1. <?php
  2. header('Content-type: image/jpeg');
  3. // Можно вывести картинку
  4. $content = implode ( "", file ( 'image.jpg' ) );
  5. echo $content;
  6. // Полученные данные можно отлажить куда-нибудь
  7. $fileName="data.txt";
  8. if (strlen($_GET["add"])> 0){
  9.     $fh = fopen($fileName, "a+");
  10.     fwrite($fh, urldecode($_GET["add"])." ".date("H:i:s")."\n");
  11.     fclose($fh);
  12. }
  13. ?>
Недостатки метода отправки данных сервер с помощью тега img:
  1. только запросы get;
  2. вся отладка на плечи кодера.