Этот ответ охватывает много вопросов, поэтому он разделен на три части:
- Как использовать прокси-сервер CORS для решения проблемы «Нет заголовка Access-Control-Allow-Origin»
- Как избежать предполетной проверки CORS
- Как исправить «заголовок Access-Control-Allow-Origin не должен быть шаблонными» проблемами
Как использовать прокси-сервер CORS для решения проблемы «Нет заголовка Access-Control-Allow-Origin»
Если вы не контролируете сервер, на который отправляет запрос ваш код 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/ . Таким образом, вместо того, чтобы добавлять префикс URL вашего запроса к https://cors-anywhere.herokuapp.comпрефиксу, вместо этого укажите 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, потому что в этом случае прокси также отправляет обратно Access-Control-Allow-Headersи Access-Control-Allow-Methodsзаголовки , необходимые , чтобы сделать предполетной успешным.
Как избежать предполетной проверки CORS
Код в вопросе запускает предварительную проверку CORS, поскольку отправляет Authorizationзаголовок.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_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_inURL.
Ответ, который браузер должен видеть на этот 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запросов. В этом случае другие серверы обычно отвечают кодом состояния 405 «Метод не разрешен».
Таким образом, вы никогда не сможете отправлять 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заголовка ответа равно *. Вместо этого значение в этом случае должно точно соответствовать происхождению кода вашего внешнего интерфейса http://127.0.0.1:3000.
См. Учетные запросы и подстановочные знаки в статье MDN HTTP control access (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-*заголовки ответа заголовки. Вы никогда не хотите отправить их в запросе. Единственный эффект, который будет иметь место, - это запустить браузер для предварительной проверки.