Кросс-доменные ajax-запросы и причем здесь php

декабрь 2 , 2016

Однажды я писал статью как создавать встраиваемые виджеты на нативном 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-сертификат на своем сайте.

Заходите в группу в контакте - https://vk.com/webdevkin
Анонсы статей, обсуждения интернет-магазинов, vue, фронтенда, php, гита.
Истории из жизни айти и обсуждение кода.
Как Вам статья? Оцените!