Несколько раз у меня уже возникала мысль о реализации кроссдоменных запросов между своими сервисами, однако толково настроить получалось плохо. Давайте уже наконец-то разберемся в этой теме.
Для начала, рассмотрим пример:
У вас есть сайт «А», на пример, реализованный на Laravel и vue.js, который реализует определенную логику работы с какими-либо данными. Сейчас вы, в рамках одного сервиса (в данном случае, несколько микро сервисов решающих разные задачи для одного большого проекта), создаете сайт «Б», которому необходимо работать с той же базой данных и использовать часть функционала сайта «А».
Как решить этот вопрос? Естественно вы можете повторно реализовать необходимый функционал на сайте «Б» и подключиться к базе сайта «А». Но в этом есть свои существенные минусы, как минимум это:
- Вы, в рамках одной системы, дублируете код, который вы написали ранее.
- Вы используете прямой доступ к БД из двух разных мест, это существенно усложнит поиск ошибок, если такие возникнут и такой подход считается далеко не «лучшей практикой».
Так же, у вас есть ещё один вариант реализации (да, это первое, что пришло вам в голову) — jsonp. Но особенности этого метода заключаются в некоторой сложности реализации:
- Высокие требования к безопасности данного подхода
- Требования к изменению кода уже написанного ранее для сайта «А».
- Метод позволят только получить данные, если вам, к примеру требуется отправить информацию методом POST, при помощи jsonp вы этого сделать не сможете.
- Уязвимость к инъекциям — вы должны полностью доверять серверу, от которого получаете данные, ведь вы будете выполнять весь код, который вам от него приходит.
Но есть вариант лучше, проще, так как не требует внесения изменений на сайте «А» и является более безопасным подходом, это кроссдоменные запросы или CORS — Cross-origin resource sharing (в переводе: совместное использование ресурсов между разными источниками).
Суть метода очень проста: для того, чтобы серверу «А» получить или отправить данные на сервер «Б», достаточно на сервере «Б» установить «разрешение» на получение и ответ на запросы с сервера «А». Делается это следующим образом: в заголовках ответа на сервере «Б» вам необходимо установить следующие записи:
|
//Сначала разрешим принимать и отправлять запросы на сервер А header('Access-Control-Allow-Origin: www.serverAdomain.ru'); //Установим типы запросов, которые следует разрешить (все неуказанные будут отклоняться) header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE'); //Разрешим передавать Cookie и Authorization заголовки для указанновго в Origin домена header('Access-Control-Allow-Credentials: true'); //Установим заголовки, которые можно будет обрабатывать header('Access-Control-Allow-Headers: Authorization, Origin, X-Requested-With, Accept, X-PINGOTHER, Content-Type'); |
В большинстве случаев, для выполнения простых кроссдоменных запросов вам будет достаточно установить только заголовок Origin
, но если вы пишите полноценное SPA приложение, которое требует авторизации, хранения Cookies и пересылки данных в обе стороны, вам понадобятся все указанные заголовки.
В Laravel очень удобно предусмотрен механизм обработки запросов при помощи middleware, если вы используете данный фреймворк вы можете легко создать middleware для обработки CORS запросов. Ниже приведен пример такого способа:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Response; class Cors { /** * Массив доменов, с которых будем принимать запросы. * * @var array */ protected $domains = [ 'http://serverA.ru', 'http://serverB.ru', 'http://serverC.ru', ]; /** * Метод, который обрабатывает все запросы, приходящие на сервер. * * @param \Illuminate\Http\Request $request * @param Closure $next * @return Response */ public function handle($request, Closure $next) { // проверим, присутствует ли заголовок HTTP_ORIGIN в запросе // и разрешен ли домен $origin = $request->headers->get('Origin'); if(!$origin || !in_array($origin, $this->domains, true)) { return new Response('Forbidden', 403); } //если есть, то устанавливаем нужные заголовки return $next($request) ->header('Access-Control-Allow-Origin', $origin) ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE') ->header('Access-Control-Allow-Credentials', 'true') ->header( 'Access-Control-Allow-Headers', 'Authorization, Origin, X-Requested-With, Accept, X-PINGOTHER, Content-Type' ); } } |
Через данный middleware, как через фильтр, будут проходить все запросы, которые приходят на сервер, и он будет обрабатывать только те запросы, которые приходят с одного из доменов, который присутствует в массиве
$domains
.
Можно немного модифицировать метод и получать массив $domains
из базы данных, а добавление новых доменов вывести в административную часть сайта и таким образом дать возможность администратору сайта самому добавлять необходимые домены и не отвлекать вас от работы.
Таким простым способом вы можете использовать одну серверную часть для нескольких ваших приложений, делая кроссдоменные запросы.
comments powered by HyperComments