Ajax кроссдоменно

JavaScript: Получить параметры GET запроса

Всем привет. Тема сегодняшней заметки: ajax кроссдоменно, без Jquery. По соображениям безопасности, объект XMLHttpRequest имеет неприятное ограничение — нельзя посылать ajax запросы на домены, отличные от домена, на котором выполняется скрипт, формирующий запрос. То есть нельзя послать ajax запрос с домена domain1.ru на domain2.ru. В будущем, кстати это ограничение собираются убрать. Почему? Потому что люди уже давно научились обходить эти ограничения и фактически это ограничение не столько спасает, сколько мешает нормальным разработчикам. Но на данный момент ситуация требует "почесать репу".

Но если вам неохота, то в конце статьи приведен листинг функции, позволяющий посылать запросы ajax кроссдоменно

Вообще технологии ajax уже хренова куча лет, но вот такую попупулярность она получила сравнительно недавно. Что такое ajax — я рассказывать в этой заметке не буду, она о другом. Итак, если ограничение на обращение к другому домену накладывает сам объект XMLHttpRequest — значит, нужно тупо обойтись без него! Нет это не шутка, и более менее знающие люди меня уже понимают

Когда в браузере загружается обычная страница, даже без JavaScript — она уже посылает на сервер целую кучу фоновых запросов, которые выполняются асинхронно загрузке самой странице… да — да я имею ввиду запросы для файлов css, запросы атрибутов src — тегов: img, iframe, object, embed, link… и ещё кучу подобных. Идея ясна? Кстати атрибут src — тега скрипт — это тоже такой же фоновый, асинхронный запрос. И заметьте, что даже если файлы картинок, стилей или скриптов, размещены на других доменах — никакие кроссбраузерные ограничения на их загрузку не влияют.

Из этого вывод:

ajax кроссдоменный GET-запрос можно послать даже с помощью картинки! Сложность в другом — как обработать ответ.

Ajax кроссдоменно

Давайте рассмотрим сдедующий алгоритм. Что бы послать запрос ajax кроссдоменно, а потом иметь возможность обработать полученные данные, мы динамически, с помощью того же Javascript создадим тег SCRIPT. Так же динамически назначим ему нужный адрес, укажем callback функцию, которая обработает полученные данные, а когда запрос загрузится — удалим к хренам, созданный нами тег SCRIPT, потому что запрос у нас может быть и не один, а целая куча.

Значит нам нужно решить пару не совсем простых задач:

  1. Как понять что ответ пришёл, что бы удалить тег SCRIPT?

  2. Как обработать ответ сервера и что такое callback функция?

Первая решается следующим образом: тег SCRIPT, как и все нормальные вещи, которые подгружаются помимо основной страницы имеет событие onload, но в IE это не прокатит. В IE воспользуемся событием onreadystatechange ( да, в IE оно есть и у элемента SCRIPT) и свойством readyState. И поняв, когда загрузка произошла — удаляем подопытного. В общем, смотрим листинг ниже:

 

// Netscape, Opera

if(navigator.appName !== "Microsoft Internet Explorer") { 

  // Используем событие load:

  scriptTag.onload = function() {

    scriptTag.parentNode.removeChild(scriptTag);

  }

       

} else {

  // Microsoft Internet Explorer

  scriptTag.onreadystatechange = function() {

    // Используем свойство readyState:

    if(scriptTag.readyState === 'loaded'){

      scriptTag.parentNode.removeChild(scriptTag);

    }

     

  }

}

Далее, как же нам обработать то, что загрузится? Есть такой вариант: в строке запроса атрибута src — указываем имя некой функции, которая должна выполниться, когда данные станут доступны, например "getServerTime" :
http://yourdomain.ru/servertime.php?callback=getServerTime
А в серверном скрипте мы сможем получить её имя из $_GET['callback']. Давайте напишем следующий код для серверной части нашего скрипта:

Серверная сторона

 

<?php

header('Content-type: text/javascript; charset=utf-8');

 

if(isset($_GET['callback']))

{

    echo $_GET['callback'].'({data : "'.date("Y-m-d H:i:s", time()).'"});';

}

 

?>

Этот код просто возвратит строку типа: getServerTime("2011-10-02 19:52:04"); При условии, конечно, что была передана GET — переменная callback со значением getServerTime. То есть мы сделали так, что серверный скрипт, как бы поместил результат своей работы (в нашем случае текущую дату и время) вместо аргумента, указанной функции.

Имейте ввиду IE не любит косяков с MIME — типами! Если указанный тип данных не будет соответствовать фактическому, в IE возможны глюки.

Что нам даст эта строка в уже загруженном теге SCRIPT ? — Ошибку! Конечно, если у нас не определена в Javscript — е функция getServerTime — имя которой мы указали, как callback. В общем нам осталось просто опредилить эту функцию. В нашем случае она будет просто выводить свой единственный аргумент как содержимое некоего html — элемента:

 

function getServerTime(time) {

    document.getElementById("timed").innerHTML = "<h3>Серверное время: " + time.data + "</h3>";

    return true;

}

А ещё, то что мы с вами только что сделали — нынче называют модным словом JSONP

Конечно это всё равно не полная свобода — мы ограничены типом запросов: GET но всё же это лучше чем ничего. Но даже это ограничение преодолимо, но об этом я, возможно расскажу в будущем. И на конец полный листинг клиентской стороны :

Клиентская сторона

 

<!DOCTYPE HTML>

<html>

<head>

<meta charset="utf-8">

<title>Документ без названия</title>

 

<script type="text/javascript">

// ... Определение функции getJsonp...

</script>

 

<script type="text/javascript">

 

function getServerTime(time) {

    document.getElementById("timed").innerHTML = "<h3>Серверное время: " + time.data + "</h3>";

    return true;

}

 

window.onload = function() {   

    getJsonp("хттп://yourdomain.ru/servertime.php", "getServerTime", true);

}

</script>

 

 

</head>

 

<body>

    <div id="timed"></div>

</body>

 

</html>

Выше, из за особенностей подсветки синтаксиса кода — я не указал реализацию функции для создания кроссдоменных ajax запрсов. Вот её полный листинг:

Функция реализующая ajax кроссдоменно

 

/*

 * getJsonp - создаёт кроссдоменный асинхр. запрос

 * param@ url:string - адрес серверного файла

 * param@ callback:string - имя функции-обработчика ответа.

 */

function getJsonp(/*string*/url,/*string*/callback, /*bool*/nocache)

{

    var scriptTag = document.createElement("SCRIPT");

    scriptTag.src = url + "?callback=" + callback;

     

    if(typeof nocache !== undefined ) {

        scriptTag.src += "&nocache=" + (new Date()).getTime();

    }                                               

                                                  

  document.body.appendChild(scriptTag);

     

  // Netscape, Opera

    if(navigator.appName !== "Microsoft Internet Explorer") { 

           

        scriptTag.onload = function() {

            scriptTag.parentNode.removeChild(scriptTag);

        }

         

    } else {

        // Microsoft Internet Explorer

        scriptTag.onreadystatechange = function() {

             

            if(scriptTag.readyState === 'loaded'){

                scriptTag.parentNode.removeChild(scriptTag);

            }

             

        }  

    }

}

Праметры:

  1. URL — серверного скрипта

  2. callback — имя функции обработчика данных

  3. nocache — запрет кеширования ответа

 

Возможно Вас заинтересуют эти материалы

Javascript выпадающий список

Часто на форумах втречаются вопросы как сделать динамический Javascript выпадающий список? Да ещё с возможностью

Javascript динамическая html таблица

Понадобилось мне в одном проекте на днях сделать html таблицу, которую бы выводил серверный php

Свои события или observer на Javascript

В этой статье, я по сути "убил двух зайцев" - Написал интересный и полезный Javascript