Ця відповідь охоплює багато підстав, тому її поділяють на три частини:
- Як використовувати CORS проксі , щоб обійти «No Access-Control-Allow-Origin заголовок» проблеми
- Як уникнути передпольоту CORS
- Як виправити проблеми з заголовком "Access-Control-Allow-Origin" не повинно бути підстановкою "
Як використовувати CORS проксі , щоб обійти «No Access-Control-Allow-Origin заголовок» проблеми
Якщо ви не керуєте сервером, на який ви відправляєте запит на код frontend JavaScript, а проблема з відповіддю з цього сервера полягає лише у відсутності необхідного Access-Control-Allow-Origin
заголовка, ви все одно можете приступити до роботи - зробивши запит через Проксі CORS. Щоб показати, як це працює, спочатку ось якийсь код, який не використовує проксі-сервер CORS:
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Причина catch
потрапляння блоку в це те, що браузер не дозволяє цьому коду отримати доступ до відповіді, з якої повертається https://example.com
. І чому браузер робить це, у відповіді не вистачає Access-Control-Allow-Origin
заголовка відповіді.
Тепер ось такий самий приклад, але лише із доданим проксі-сервером CORS:
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Примітка. Якщо https://cors-anywhere.herokuapp.com вимкнений або недоступний, коли ви спробуєте це, то дивіться нижче, як розгорнути власний сервер CORS Anywhere на Heroku всього за 2-3 хвилини.
Другий фрагмент коду, наведений вище, може успішно отримати відповідь, оскільки прийняття URL-адреси запиту та зміна його на https://cors-anywhere.herokuapp.com/https://example.com - шляхом простої префіксації URL-адреси проксі - викликає запит на отримання проксі-сервера, який:
- Пересилає запит на
https://example.com
.
- Отримує відповідь від
https://example.com
.
- Додає
Access-Control-Allow-Origin
заголовок відповіді.
- Передає цю відповідь із доданим заголовком назад до запитуючого коду фронтеду.
Потім браузер дозволяє коду прямого доступу отримати доступ до відповіді, оскільки ця відповідь із Access-Control-Allow-Origin
заголовком відповіді - це те, що бачить браузер.
Ви можете легко запустити власний проксі, використовуючи код з https://github.com/Rob--W/cors-anywhere/ .
Ви також можете легко розгорнути власний проксі для Heroku буквально лише за 2-3 хвилини з 5 командами:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
Після запуску цих команд у вас з’явиться власний сервер CORS Anywhere, на якому працює, наприклад, https://cryptic-headland-94862.herokuapp.com/ . Тож замість того https://cors-anywhere.herokuapp.com
, щоб префіксувати URL-адресу вашого запиту за допомогою , префікс, а не URL-адресу для власного примірника; наприклад, https://cryptic-headland-94862.herokuapp.com/https://example.com .
Тож якщо ви спробуєте скористатись https://cors-anywhere.herokuapp.com, ви виявите, що це знищено (що це іноді буде), тоді подумайте про те, щоб отримати обліковий запис Heroku (якщо цього ще не зробити) та візьміть 2 або 3 хвилини, щоб виконати вказані вище дії, щоб розгорнути власний сервер CORS Anywhere на Heroku.
Незалежно від того, чи запускаєте ви свій власний або використовуєте https://cors-anywhere.herokuapp.com чи інший відкритий проксі, це рішення працює навіть у тому випадку, коли запит викликає браузери для виконання попереднього OPTIONS
запиту CORS - тому що в цьому випадку proxy також надсилає назад Access-Control-Allow-Headers
і Access-Control-Allow-Methods
заголовки, необхідні для успішного передпольоту.
Як уникнути передпольоту CORS
Код у запитанні запускає попередній політ CORS - оскільки він надсилає Authorization
заголовок.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Prefliisted_requests
Навіть без цього Content-Type: application/json
заголовок також спровокує передполіт.
Що означає "передполіт": перш ніж браузер спробує POST
ввести код у запитанні, він спочатку надішле OPTIONS
запит на сервер - щоб визначити, чи сервер не бажає приймати перехресне походження, POST
що включає заголовки Authorization
та Content-Type: application/json
.
Це досить добре працює з невеликим сценарієм curl - я отримую свої дані.
Щоб правильно пройти тестування curl
, ви повинні наслідувати OPTIONS
запит перед полетом, який браузер надсилає:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
… https://the.sign_in.url
Замінено на будь-яку фактичну sign_in
URL-адресу.
Відповідь, яку браузер повинен бачити з цього OPTIONS
запиту, повинна містити заголовки на зразок цього:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Якщо OPTIONS
відповідь не включає ці заголовки, браузер зупиниться прямо там і навіть не намагатиметься надіслати POST
запит. Також код статусу HTTP для відповіді повинен бути 2xx - як правило, 200 або 204. Якщо це будь-який інший код статусу, браузер зупиниться саме там.
Сервер у запитанні відповідає на OPTIONS
запит кодом статусу 501, що, мабуть, означає, що він намагається вказати, що він не реалізує підтримку OPTIONS
запитів. Інші сервери зазвичай відповідають у цьому випадку кодом статусу "Метод не дозволений".
Таким чином, ви ніколи не зможете робити POST
запити безпосередньо на цей сервер з вашого коду JavaScript для прямого доступу, якщо сервер відповість на цей OPTIONS
запит номером 405 або 501 або чим-небудь іншим, ніж 200 або 204, або якщо не відповідає на необхідні заголовки відповідей.
Способом уникнути запуску передпольоту для даної справи буде такий:
- якщо сервер не потребував
Authorization
заголовка запиту, але замість цього (наприклад) покладався на дані аутентифікації, вбудовані в тіло POST
запиту або як параметр запиту
- якщо сервер не вимагав, щоб
POST
тіло мав Content-Type: application/json
тип медіа, але замість цього прийняв POST
тіло як application/x-www-form-urlencoded
з параметром, названим json
(або будь-яким іншим), значенням якого є дані JSON
Як виправити проблеми з заголовком "Access-Control-Allow-Origin" не повинно бути підстановкою "
Я отримую ще одне повідомлення про помилку:
Значення заголовка "Access-Control-Allow-Origin" у відповіді не повинно бути символом "*", коли в режимі облікових даних запиту є "включити". Таким чином, джерело " http://127.0.0.1:3000 " не має доступу. Режим облікових даних запитів, ініційований XMLHttpRequest, керується атрибутом withCredentials.
Для запиту, що включає в себе облікові дані, веб-переглядачі не дозволяють вашому коду JavaScript для прямого доступу отримати доступ до відповіді, якщо значення Access-Control-Allow-Origin
заголовок відповіді є *
. Замість того, щоб значення в цьому випадку повинен точно відповідати походження вашого FRONTEND кодексу, в http://127.0.0.1:3000
.
Див. Запити та посвідчення підтверджених даних у статті контролю доступу HTTP MDN (CORS).
Якщо ви керуєте сервером, на який надсилаєте запит, то загальним способом вирішення цього випадку є налаштування сервера на прийняття значення Origin
заголовка запиту та відлуння / відображення цього значення у Access-Control-Allow-Origin
заголовку відповіді. Наприклад, з nginx:
add_header Access-Control-Allow-Origin $http_origin
Але це лише один приклад; інші (веб) серверні системи надають аналогічні способи відображення значень походження.
Я використовую Chrome. Я також спробував використовувати цей плагін Chrome CORS
Цей плагін Chrome CORS, очевидно, просто просто вводить Access-Control-Allow-Origin: *
заголовок у відповідь, яку бачить браузер. Якщо плагін був розумніший, ніж це робило б це встановити значення цього підробленого Access-Control-Allow-Origin
відповідь заголовка до фактичного початку вашого зовнішнього інтерфейсу коду JavaScript, http://127.0.0.1:3000
.
Тому уникайте використання цього плагіна навіть для тестування. Це просто відволікання. Якщо ви хочете перевірити, які відповіді ви отримуєте від сервера, без браузера їх фільтрувати, вам краще скористатися, curl -H
як описано вище.
Що стосується коду JavaScript на передній частині для fetch(…)
запиту у питанні:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Видаліть ці рядки. Ці Access-Control-Allow-*
заголовки відповіді заголовки. Ніколи не хочеш надсилати їх у запиті. Єдиний ефект, який потрібно мати, - це запустити веб-переглядач перед полетом.