Кросс-доменные ajax-запросы и причем здесь php
Однажды я писал статью как создавать встраиваемые виджеты на нативном javascript и php. И все бы хорошо, но в ней не затронул один момент. Такие виджеты использовать на собственном сайте можно, но интереснее создавать их для сторонних ресурсов. Но в таком случае нужные данные браузер должен подгружать с другого домена - это и есть кросс-доменные ajax-запросы.
С точки зрения фронтенд-программистов кросс-доменные запросы ничем не отличаются от обычных. А вот на бекенде разница есть. Почему с ними не все так просто и как их реализовать - об этом читайте в статье.
Пробуем получить данные с другого домена
Для простоты рассмотрим get-запросы. Допустим, на сервере лежит некий html-файлик, который нам край как нужно загрузить ajax-ом с другого домена. Пусть это файл https://webdevkin.ru/examples/cross_domain/template.html. Откройте его и убедитесь, что он действительно доступен - вот ссылка (откроется в новой вкладке). Это обычный div с текстом "content from template.html".
А теперь давайте получим эту html-ку ajax-ом прямо из консоли браузера.
Не будем париться с нативным javascript-ом, а дернем запрос с помощью jQuery.get() и выведем в консоль то, что получили в ответ с сервера.
$.get('https://webdevkin.ru/examples/cross_domain/template.html', function(responce) {console.log(responce)});
Откройте прямо сейчас developer tools в браузере и на вкладке console выполните этот запрос.
Вы увидите примерно следующее
Все замечательно, отправили запрос, получили ответ. Казалось бы, что может быть проще? А теперь зайдите на любой другой сайт, где подключен jQuery и попробуйте проделать то же самое. Только не на https-сайт, почему - узнаете в конце статьи.
Я, например, проверял запросы на футбольном сайте bombardir.ru. И заодно подивился, какой только дряни не вываливается в консоль даже на таких достаточно известных сайтах. Впрочем, разговор не про это.
Выполните запрос с другого домена и Вы увидите в консоли уже не такую благостную картину.
Говорит, невозможно загрузить, данных нет и вообще печаль.
Если откроете вкладку Network и найдете там соотвествующий запрос, то увидите, сервер даже вернул нам 200 ОК
А содержимого файла нет. В чем подвох?
Что пошло не так и каково будет решение
Подвох в том, что политика интернетов не разрешает браузерам вытаскивать данные с каких угодно ресурсов.
Кроме тех случаев, когда эти ресурсы сами заинтересованы в раздаче конкретных данных.
Наш случай именно такой.
Чтобы дать разрешение на использование html-файлика откуда угодно, нужно при запросе оного файла отправлять http-заголовок Access-Control-Allow-Origin: *
Теперь вопрос, как это сделать. Если у Вас (или же у админов) есть доступ к nginx, то одним способом будет настроить прокидывание этого заголовка средствами веб-сервера. Вы идете к админам с соответствующей просьбой или гуглите сами нужные конфиги для Вашего веб-сервера.
Если же этого доступа нет, как например, у практически любого хостинг-провайдера на недорогом тарифе, то нужно выкручиваться самостоятельно. И здесь на помощь приходит php. Идея в том, чтобы закинуть нашу html-ку в php-файл, который и прокинет заголовок, и отдаст нужное содержимое.
Получится так, создаем файл template.php и первой строкой запишем php-команду
header('Access-Control-Allow-Origin: *');
А дальше html-код
content from template.php
То есть содержимое template.php будет таким, не забудьте про php-шные вопросы и скобки
Файл на webdevkin-е создан и лежит здесь (откроется в новой вкладке). Давайте теперь попробуем запросить его с другого домена и посмотрим, что будет
$.get('https://webdevkin.ru/examples/cross_domain/template.php', function(responce) {console.log(responce)});
Как видно, все работает прекрасно - файл загружен!
Заглянем на вкладку Network.
Обратите внимание, в блоке Response Headers появился интересующий нас заголовок Access-Control-Allow-Origin: *
В целом статья закончена. Осталось собрать мысли в кучу и добавить еще немного информации.
Обобщаем и подводим итоги
- 1. Нельзя просто так запросить ajax-ом любой ресурс с другого домена
- 2. Отправляйте заголовок Access-Control-Allow-Origin для всех ресурсов, к которым нужен доступ откуда угодно
- 3. Делайте это средствами веб-сервера или php
- 4. На php этот заголовок отправляется командой header('Access-Control-Allow-Origin: *')
- 5. Access-Control-Allow-Origin: * - разрешить доступ всем доменам, Access-Control-Allow-Origin: site.ru - только домену site.ru
- 6. Access-Control-Allow-Origin отправляется в самом начале php-файла, еще до вывода других данных (как впрочем, и любые другие http-заголовки)
- 7. "Ресурс" - это не только файл с html-разметкой, но и любой url, к которому идет ajax-запрос, например, получение json-данных или post-запрос на добавление строки в таблицу БД
И последнее, вынес отдельно. Я не зря просил выполнять запросы именно с http-сайта. С https не получится подгрузить данные с http по другой причине - mixed content. А webdevkin.ru пока что http-сайт (updated: уже нет, перенес webdevkin.ru на https)
Вот что увидите в консоли, попытавшись выполнить тот же запрос с любого https-сайта.
Поэтому если Вы собираетесь заниматься встраиваемыми виджетами или чем-то подобным, Вам обязательно нужно поставить ssl-сертификат на своем сайте.
Истории из жизни айти и обсуждение кода.