AJAX. Кроссдоменые запросы. CURL.

Кроссдоменые запросы

Кроссдоменый запрос - это запрос ресурса со стороннего домена.

Обычно запрос XMLHttpRequest может делать запрос только в рамках текущего сайта. При попытке использовать другой домен/порт/протокол – браузер выдаёт ошибку.

Пример правила ограничения домена(SOP)

Правило ограничения домена (Same Origin Pliicy, «Принцип одинакового источника») - это важная концепция безопасности на стороне клиента, для языка программирования JavaScript. Политика разрешает сценариям, находящимся на страницах одного сайта, доступ к методам и свойствам друг друга без ограничений, но предотвращает доступ к большинству методов и свойств для страниц на разных сайтах.

Одинаковые источники - это источники, у которых совпадают три признака:

Концепция правила ограничения домена появилась во времена Netscape Navigator 2.0.

Для иллюстрации данного правила посмотрим на следующую таблицу, которая даёт обзор типичных проверок. К примеру, запрос производится со следующего URL http://www.example.com/dir/page.html.

Сравниваемый URL Проверка Причина
http://www.example.com/dir/page.html Соответствует Тот же протокол и домен
http://www.example.com/dir2/other.html Соответствует Тот же протокол и домен
http://username:password@www.example.com/dir2/other.html Соответствует Тот же протокол и домен
http://www.example.com:81/dir/other.html Не соответствует Тот же протокол и домен, но другой порт
https://www.example.com/dir/other.html Не соответствует Отличается протокол
http://en.example.com/dir/other.html Не соответствует Отличается домен
http://example.com/dir/other.html Не соответствует Отличается домен (требуется полное соответствие)
http://v2.www.example.com/dir/other.html Не соответствует Отличается домен (требуется полное соответствие)
http://www.example.com:80/dir/other.html Не определено Явное указание порта. Зависит от реализации в браузере.

Существует современный стандарт который предусматривает кроссдоменные запросы и многое другое. Большинство возможностей этого стандарта уже поддерживаются всеми современными браузерами.

Cross-origin resource sharing (CORS «совместное использование ресурсов между разными источниками») - технология современных браузеров, которая позволяет предоставить веб-странице доступ к ресурсам другого домена.
w3c CORS

Идея проста – пусть клиент шлет AJAX-запрос к чужому серверу. Браузер добавит в запрос особые заголовки с информацией о том, что запрос с другого домена. На их основании сервер решит, как обрабатывать такой запрос, и добавит особые заголовки в ответ.

Техническая реализация несколько сложнее. Спецификация CORS налагает специальные ограничения на запросы. Запросы в ней делятся на два вида: “простые” и “сложные”.

Простыми считаются запросы, если они удовлетворяют следующим двум условиям:

«Непростыми» считаются все остальные, например, запрос с методом PUT или с заголовком Authorization не подходит под ограничения выше.

Принципиальная разница между ними заключается в том, что «простой» запрос можно сформировать и отправить на сервер и без XMLHttpRequest, например при помощи HTML-формы.

Если ваш запрос удовлетворяет этим критериям, можно слать AJAX запрос к другому домену из любого современного браузера. При этом браузер добавит заголовок Origin с адресом страницы, откуда инициирован запрос. Подделать заголовок скриптом не удастся.

В кросс-доменный запрос браузер автоматически добавляет заголовок Origin, содержащий домен, с которого осуществлён запрос.

Сервер, получив на обработку подобный запрос, должен прочесть Origin и решить, как его обрабатывать. Заголовок ответа Access-Control-Allow-Origin регулирует, с какого домена разрешено запрашивать данные. Это может быть как веб-адрес, так и знак "звездочки", если разрешено всем.

Несколько разных адресов через запятую, к сожалению, не поддерживаются для заголовка Access-Control-Allow-Origin

В случае запроса на http://foo.com/folderimg с http://mysite.ru/page заголовки будут примерно такие:

				
GET /folderimg
Host: foo.com
Origin: http://mysite.ru
				
			

Сервер должен, со своей стороны, ответить специальными заголовками, разрешает ли он такой запрос к себе.

Если сервер разрешает кросс-доменный запрос с этого домена – он должен добавить к ответу заголовок Access-Control-Allow-Origin, содержащий домен запроса (в данном случае «mysite.ru») или звёздочку *.

				
200 OK HTTP/1.1
Access-Control-Allow-Origin: http://mysite.ru
Content-Type: text/html; charset=utf-8

<h1>Welldone</h1>
				
			
Только при наличии такого заголовка в ответе – браузер сочтёт запрос успешным, а иначе JavaScript получит ошибку.
Пример простого запроса

Если Access-Control-Allow-Origin нет, то браузер считает, что разрешение не получено, и завершает запрос с ошибкой.

При таких запросах не передаются куки и заголовки HTTP-авторизации.

В кросс-доменном XMLHttpRequest можно указать не только GET/POST, но и любой другой метод, например PUT, DELETE.

Когда-то никто и не думал, что страница сможет сделать такие запросы. Поэтому ряд веб-сервисов написаны в предположении, что «если метод – нестандартный, то это не браузер». Некоторые веб-сервисы даже учитывают это при проверке прав доступа.

Чтобы пресечь любые недопонимания, браузер использует предзапрос в случаях, когда:

Любое из условий выше ведёт к тому, что браузер сделает два HTTP-запроса.

Первый запрос называется «предзапрос» (английский термин «preflight»). Браузер делает его целиком по своей инициативе, из JavaScript мы о нём ничего не знаем, хотя можем увидеть в инструментах разработчика.

Этот запрос использует метод OPTIONS. Он не содержит тела и содержит название желаемого метода в заголовке Access-Control-Request-Method, а если добавлены особые заголовки, то и их тоже – в Access-Control-Request-Headers.

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

На этот запрос сервер должен ответить статусом 200, без тела ответа, указав заголовки Access-Control-Allow-Method: метод и, при необходимости, Access-Control-Allow-Headers: разрешённые заголовки.

Дополнительно он может указать Access-Control-Max-Age: sec, где sec – количество секунд, на которые нужно закэшировать разрешение. Тогда при последующих вызовах метода браузер уже не будет делать предзапрос.

Пример сложного запроса

Пример сложного запроса →(см. папку example/)

cURL

cURL - (распространяемая по лицензии MIT), кроссплатформенная служебная программа командной строки, позволяющая взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.

С приходом обновления Redstone 4 «April 2018 Update» (версия 1803) для Windows 10, программа cURL была включена в состав этой операционной системы.

https://curl.haxx.se/

Программа cURL может автоматизировать передачу файлов или последовательность таких операций. Например, это хорошее средство для моделирования действий пользователя в веб-обозревателе.

Программа поддерживает протоколы: FTP, FTPS, HTTP, HTTPS, TFTP, SCP, SFTP, Telnet, DICT, LDAP, а также POP3, IMAP и SMTP. Также cURL поддерживает сертификаты HTTPS, методы HTTP POST, HTTP PUT, загрузку на FTP, загрузку через формы HTTP.

Поддерживаемые методы аутентификации: базовая, дайджест, NTLM и Negotiate для HTTP, а также Kerberos для FTP.

Возможно возобновление передачи файла с места обрыва (при поддержке протоколом), туннелирование через HTTP-прокси, поддержка HTTP-Cookie.

Первоначально cURL разработан как средство перемещения файлов между конечными точками с использованием различных протоколов, таких как FTP, HTTP, SCP и другие. Сначала это была утилита командной строки, но теперь это также библиотека с привязками более чем к 30 языкам. Так что теперь, вместо того чтобы использовать cURL из командной строки, можно создавать приложения, которые включают в себя эти важные функции. Библиотека libcurl также переносима и поддерживает Linux, IBM AIX, BSD, Solaris и многие другие варианты UNIX.

Ниже будут представлены далеко не все параметры и возможности cURL, но они дают понять, что это больше чем просто утилита командной строки для Linux или Windows. Это набор библиотек, в которых реализуются базовые возможности работы с URL страницами и передачи файлов. Библиотека поддерживает работу с большим количеством протоколов. Она отлично подходит для имитации действий пользователя на страницах и других операций с URL адресами.

Проверка URL

Одним из наиболее распространенных и простейших применений cURL - это проверка состояния по текущему URL.

					
curl https://zamt.000webhostapp.com/
					
				

Эта команда будет отображать содержимое URL на вашем терминале.

Сохранение вывода

Выход команды cURL может легко сохранить в файл, добавив опцию -o и указав имя файла под которым сохраниться вывод

					
curl -o output.html https://zamt.000webhostapp.com/
					
				

Если требуется, чтобы полученный файл назывался так же, как и файл на сервере, используйте опцию -O(!!ЗАГЛАВНАЯ!!)

					
curl -O https://upload.wikimedia.org/wikipedia/commons/d/d2/Internet_map_1024.jpg
					
				

Анализ заголовков

Не всегда нам обязательно нужно содержимое страницы. Иногда могут быть интересны только заголовки. Чтобы вывести только их есть опция -I

					
curl -I https://zamt.000webhostapp.com/
					
				

Аутентификация

Если на сервере требуется аутентификация одного из распространенных типов, например, SSH или FTP, то curl очень просто может справиться с такой задачей. Для указания данных аутентификации просто укажите их через двоеточие в опции -u

					
curl -u electro:electro ftp://ftp.ntsomz.ru/
					
				

В данном примере мы получим список файлов и каталогов по текущему адресу. Обратите внимание, если Вам необходимо загрузить файл, то Вы должны использовать полный путь к файлу(не забываем про опцию -O).

					
curl -u electro:electro -O ftp://ftp.ntsomz.ru/ELECTRO_L_2/2018/July/10/1030/180710_1030.zip
					
				

Возобновление загрузки

Если загрузка была неожиданно прервана, вы можете ее возобновить с помощью опции .

					
curl -u electro:electro -O -C - ftp://ftp.ntsomz.ru/ELECTRO_L_2/2018/July/10/1030/180710_1030.zip
					
				

или --continue-at <offset> используется для продолжения работы предыдущей сессии передачи файлов с заданным смещением. При использовании FTP сервера команда SIZE не будет использована curl. Можно использовать "-C -", чтобы curl автоматически нашал место где возобновить передачу.

Так же можно воспользоваться опцией -#, которая отображает простой прогресс-бар во время загрузки заместо таблицы.

					
curl -# -u electro:electro -O -C - ftp://ftp.ntsomz.ru/ELECTRO_L_2/2018/July/10/1030/180710_1030.zip
					
				

Ограничение скорости

--limit-rate <speed> - опция задает максимальную скорость передачи данных. Этот параметр полезен, если у вас ограниченный канал и Вы не хотите его перегружать.

Скорость канала измеряется в байтах в секунду, если не использовать суффикс. Буквы 'k' или 'K' означают килобайт в секунду, 'm' или 'M' -мегабайт в секунду и 'g' или 'G' гигабайт в секунду. Например : 100K, 3m, 1G

					
curl -u electro:electro -O --limit-rate 100k ftp://ftp.ntsomz.ru/ELECTRO_L_2/2018/July/10/1030/180710_1030.zip
					
				

Отправка параметров

Вы можете отправлять любые данные методом POST. Для отправки такого запроса используйте опцию -d.

В случаи не правильного указания имени параметра или его значения скрипт вернет "ERROR"
					
curl -d "usr=admin&passwd=12345" https://zamt.000webhostapp.com/pr08post.php
					
				

-G - если эта опция включена, то все данные, указанные в опции -d будут передаваться методом GET

					
curl -d "cmd=ping" -G https://zamt.000webhostapp.com/pr08get.php
					
				
Чтобы данные примеры работали в стенах техникума необходимо дополнительно использовать опцию --proxy <[protocol://][user@password]proxyhost[:port]>, которая указывает прокси сервер.

libcurl — это библиотека API для передачи, которую разработчики могут встроить в свои программы; cURL действует как автономная обёртка для библиотеки libcurl. libcurl используется, чтобы обеспечить возможность передачи файлов (адресуемых с помощью URL) многочисленным приложениям (как открытым, так и коммерческим).

http://php.net/manual/ru/book.curl.php

PHP включена поддержка libcurl - библиотеки функций, которая позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов. В настоящее время libcurl поддерживает протоколы http, https, ftp, gopher, telnet, dict, file и ldap. libcurl также умеет работать с сертификатами HTTPS, посылать запросы к HTTP серверам методами POST и PUT, закачивать файлы по протоколам HTTP и FTP.

Работа с cURL всегда начинается с

  1. вызова curl_init(), затем
  2. устанавливаются необходимые параметры с помощью curl_setopt(), и
  3. выполняется требуемая операция вызовом curl_exec(), после чего
  4. вызовом curl_close() сеанс работы завершается.

Самый простой пример использования libcurl в PHP

				
$url = "https://ya.ru";

/* инициализация сеанса с последующим возвращением дескриптора, 
который используется с функциями  */
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url); //
/* Загружаемый URL. Данный параметр может быть также установлен 
при инициализации сеанса с помощью curl_init(). */
//$ch = curl_init($url);

curl_exec($ch); // выполнить операцию
curl_close($ch); // закрытие сеанса
				
			

В результате на станице отобразиться содержимое по адресу "https://ya.ru".
cURL. Пример 1

Прямой вывод результата работы в браузер не всегда полезене и для того чтобы результат возвращался в качестве строки из curl_exec() используется параметр CURLOPT_RETURNTRANSFER

				
$url = "https://ya.ru";
$ch = curl_init(); // инициализация сеанса с последующим возвращением дескриптора

curl_setopt($ch, CURLOPT_URL, $url); // загружаемый URL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // возврат результата в качестве строки

$out = curl_exec($ch); // выполнить запрос
curl_close($ch); // закрытие сеанса

echo $out;
				
			

cURL. Пример 2

Приведенный ниже пример использует функции cURL для сохранения страницы

				
$url = "https://ya.ru";
$path = "page.html";
$ch = curl_init(); // инициализация сеанса с последующим возвращением дескриптора
$fp = fopen($path, "w"); // файл на запись

curl_setopt($ch, CURLOPT_URL, $url); // адрес страницы
curl_setopt($ch, CURLOPT_FILE, $fp); // файловый указатель для сохранения

curl_exec($ch); // выполнить запрос
curl_close($ch); // закрытие сеанса
fclose($fp);
				
			

cURL. Пример 3

Это лишь малая часть того что может cURL