Попытаюсь упрощённо объяснить, что такое CORS, зачем он нужен и как с ним бороться. Если интересно только последнее, можно сразу листать вниз.
Возьмём для примера какой-нибудь проект типа Instagram. У него есть мобильные приложения, а значит, есть API. Скорее всего приватное. И тут появляется условный разработчик Вася. Декомпилит и реверсит приложение, достаёт все нужные эндпоинты и ключи. И думает: «а дай-ка я сделаю свой веб-клиент к инстаграмму, добавлю туда нескучных стикеров, навешаю свою рекламу и дам имя Plesnigram».
Пользователь открывает Васин веб-клиент по адресу
plesnigram.com, веб-клиент шлёт запросы на api.instagram.com. Можно гребсти бабло лопатой, паразитируя на чужой инфраструктуре. А инстаграм сидит и локти на ногах кусает — никак Васин клиент не заблокируешь же. У его пользователей айпишники-то разные. А больше никакой инфы и нет в request. И всё классно было бы у Васи в мире без CORS. Но в нашем мире первый же запрос к API выплюнет такую ошибку в консоль браузера:
Access to fetch at 'https://api.instagram.com/feed/' from origin 'http://plesnigram.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.CORS это тот механизм защиты, который не даёт Васям писать подобные клиенты без разрешения инстаграмма.
Бегло пробежавшись по тексту ошибки первой мыслью может быть: «установлю-ка я
mode: 'no-cors' да отключу его».Но грош цена была бы такому механизму защиты тогда.
no-cors для других случаев, не ваших.Надо разобраться, что происходит.
Браузер смотрит, что открыта страница
https://plesnigram.com, а запрос идёт на https://api.instagram.com. Несовпадение. Безо всяких премудростей можно запросы слать только на тот же самый origin. То есть на https://plesnigram.com/. А при несовпадении браузер сперва отошлёт pre-flight request — запрос на разведку. И принудительно выставит заголовок запроса Origin: https://plesnigram.com. Это те самые странные запросы с методом OPTIONS, которые иногда можно наблюдать во вкладке Network. Сервер инстаграмма, в свою очередь, может решить. Если разрешает этот запрос с этого источника, то он должен вернуть в ответе заголовок
Access-Control-Allow-Origin: https://plesnigram.com. Браузер сопоставляет значение этого заголовка с origin, который отправлялся ранее. И только в случае полного совпадения (включая порт, кстати) дальше на сервер отправляется запрос, который изначально задумывался. В противном случае имеем ту самую ошибку.Как бороться
1. Можно поставить в хром расширение Allow-Access-Allow-Origin: *. Оно подменяет значение вышеупомянутого заголовка на
* (любой origin). Это поможет при разработке. Не поможет, если захотите проверить с мобилки. Не поможет в проде.2. Можно, собственно, сконфигурировать сервер, чтобы он возвращал нужный заголовок. Для разработки можно обойтись
*. В проде проследите, чтобы там были только origins из белого списка.3. Можно проксировать запросы так, чтобы origin оставался тем же самым.
https://plesnigram.com/api/photos → https://api.instagram.com/photos. В проде это делается каким-нибудь nginx. Но, соответственно, у инстаграмма появится возможность с лёгкостью заблокировать ваш реверс-прокси, если ему что-то не понравится. В разработке это делается, например, с помощью http-proxy-middleware. Изучите доку своего вебпака. Прокси там уже, вероятно, встроено. Не забудьте переписать урлы эндпоинтов на относительные.Со схожей проблемой столкнётесь, кстати, когда попытаетесь читать кастомные заголовки в ответах. Но с этим теперь можно разобраться и самим.