Как стать автором
Обновить

Кросс-доменный XMLHttpRequest

Время на прочтение4 мин
Количество просмотров3.1K
Важной составляющей технологии AJAX является XMLHttpRequest. Этот объект дает возможность осуществлять HTTP-запросы к серверу без необходимости в перезагрузке страницы.

Обычно работа с XMLHttpRequest происходит следующим образом:
1. Создание экземпляра объекта XMLHttpRequest
2. Установка обработчика события, которое происходит при изменении состояния объекта (onreadystatechange)
3. Открытие соединения (open) и отправка запроса (send)

К сожалению XMLHttpRequest работает только с теми файлами, которые находятся в том же домене, что и использующая XMLHttpRequest страница. То есть запрос можно сделать только на адреса с тем же доменом, протоколом и портом, что и текущая страница. Это сделано в целях безопасности и создает проблемы, если надо получить данные/контент с другого сайта.

Недавно передо мной возникла данная проблема, было выбрано очень простое решение, речь о котором пойдет дальше.

Проксирование! Простой и наглядный метод для осуществления кросс-доменных запросов. Суть метода такова:

1. XMLHttpRequest обращается к PHP скрипту, на своем домене, передавая ему метод запроса, адрес и параметры
2. PHP скрипт, в свою очередь, выступает в роли прокси. То есть он осуществляет запрос исходя из переданных ему параметров и возвращает ответ другого сервера JS скрипту

Работа PHP скрипта, который являет собой прокси для кросс-доменного запроса, основана на CURL.

Вот собственно сам скрипт proxy.php:
<?php
header("Content-Type: text/xml; charset=windows-1251");
// параметры запроса
$method = (empty($_GET['method'])) ? 1 : $_GET['method'];
$url = $_GET['url'];
$url = (empty($_GET['url'])) ? die("no url") : $_GET['url'];
$params = $_GET['params'];
// проверим целевой домен запроса
$allowed = array(1 => "~http:\/\/(www\.)?habrahabr\.ru\/~", 2 => "~http:\/\/(www\.)?el\-egoisto\.com\/~");
$count = count($allowed);
for ($i = 1; $i <= $count; $i++)
{
if (preg_match($allowed[$i],$url))
{
// домен в списке разрешенных - отправляем запрос
$ch = curl_init();
switch ($method)
{
case 1:
// GET запрос
curl_setopt($ch, CURLOPT_URL, $url."?".$params);
break;
case 2:
// POST запрос
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
break;
}
curl_setopt($ch, CURLOPT_HEADER, 0);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch,CURLINFO_HEADER_SIZE);
$xml = substr($response,$header_size);
echo $xml;
curl_close($ch);
exit();
}
}
?>

XMLHttpRequest обращается к нему и передает 3 параметра:
1. method – 1 для GET запроса и 2 для POST
2. url – адрес запроса
3. params – параметры запроса

PHP скрипт проверяет наличие входных параметров, проверяет разрешено ли отправлять запрос на url (массив регэкспов $allowed) и собственно отправляет запрос и возвращает ответ удаленного сервера.

Из JS этот PHP скрипт используется так:

Есть 2 функции для работы с XMLHttpRequest — CreateReq и GetData. Первая – создает экземпляр объекта, а вторая – устанавливает обработчик и отправляет запрос.
function CreateReq()
{
var req = null;
if (window.XMLHttpRequest)
{
try
{
req = new XMLHttpRequest();
}
catch(e)
{
req = null;
}
}
else if (window.ActiveXObject)
{
try
{
req = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(e)
{
try
{
req = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e)
{
req = null;
}
}
}
return req;
}

function GetData(url,callback)
{
req = new CreateReq;

if(req != null)
{
req.onreadystatechange = callback;
req.open('GET', url, true);
req.send(null);
}
else alert("Произошла ошибка..");
}


Отправку GET запроса рассмотрим на примере получения кармы и силы с Хабра :)

function GetHabraMe()
{
GetData("/proxy.php?method=1&url="+encodeURIComponent("http://habrahabr.ru/api/profile/lordeg"),GetHabraCallback);
}

function GetHabraCallback()
{
if(req.readyState == 4)
{
if(req.status == 200)
{
var xmlDoc = req.responseXML;
var karma = xmlDoc.getElementsByTagName("karma").item(0).firstChild.data;
var rating = xmlDoc.getElementsByTagName("rating").item(0).firstChild.data;
var place = document.getElementById("data");
if(place != null)
{
place.innerHTML = "Карма: "+karma+"<br>Рейтинг: "+rating+";
}
}
}
return false;
}


GetHabraMe отправит GET запрос на habrahabr.ru/api/profile/lordeg, используя proxy.php и результат «вернет» в элемент с id “data”.

Отправка POST запроса происходит практически так же:

function GetPings()
{
var d_topic = document.getElementById("topic");
if (d_topic.innerHTML == "Последние треки")
{
GetData("/proxy.php?method=2&url="+encodeURIComponent("http://el-egoisto.com/frontend.php")+"&params="+encodeURIComponent("func=recent&owner=9&id=1&cutoff=48"),GetMyLastPingsCallback);
}
}

Реализацию в «боевых условиях» можно посмотреть тут – lord-phoenix.com (ссылки «current music» и «хабралордег») :)
На оригинальность не претендую, просто решил оформить решение проблемы, возникшей передо мной, в виде топика в блоге. Может кому и пригодится мой опыт.

Материалы по теме:
1. xmlhttprequest.ru
2. ru.wikipedia.org/wiki/XMLHttpRequest
3. ru.wikipedia.org/wiki/AJAX
4. ru.wikipedia.org/wiki/CURL
Теги:
Хабы:
Всего голосов 20: ↑9 и ↓11-2
Комментарии22

Публикации