Нет заголовка "Access-Control-Allow-Origin" на запрошенном ресурсе-при попытке получить данные из REST API

Я пытаюсь получить некоторые данные из REST API HP Alm. Он отлично работает с небольшим скриптом curl - я получаю свои данные.

теперь, делая это с JavaScript, fetch и ES6 (более или менее), кажется, большая проблема. Я продолжаю получать это сообщение об ошибке:

Fetch API не может загрузить . Ответ на запрос preflight не проверка контроля доступа пропуска: нет заголовка "Access-Control-Allow-Origin" присутствует на запрашиваемый ресурс. Происхождение 'http://127.0.0.1:3000 ' is поэтому доступ запрещен. Ответ имел код состояния HTTP 501. Если непрозрачный ответ служит вашим потребностям, установите режим запроса в 'no-cors', чтобы получить ресурс с отключенным CORS.

Я понимаю, что это потому, что я пытаюсь получить эти данные из моего localhost, и решение должно использовать CORS. Теперь я думал, что действительно сделал это, но каким-то образом он либо игнорирует то, что я пишу в заголовке, либо проблема в чем-то другом?

Итак, есть ли проблема с реализацией? Я делаю это неправильно? К сожалению, я не могу проверить журналы сервера. Я действительно немного застрял здесь.

function performSignIn() {

  let headers = new Headers();

  headers.append('Content-Type', 'application/json');
  headers.append('Accept', 'application/json');

  headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
  headers.append('Access-Control-Allow-Credentials', 'true');

  headers.append('GET', 'POST', 'OPTIONS');

  headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));

  fetch(sign_in, {
      //mode: 'no-cors',
      credentials: 'include',
      method: 'POST',
      headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

Я использую Chrome. Я также попытался использовать этот плагин Chrome CORS, но затем я получаю другое сообщение об ошибке:

значение заголовка "Access-Control-Allow-Origin" в ответе не должно быть подстановочного знака"*", когда режим учетных данных запроса "включить". Происхождение'http://127.0.0.1:3000 ' поэтому не допускается доступ. Режим учетных данных запросов, инициированных XMLHttpRequest управляется атрибутом withCredentials.

4 ответов


этот ответ охватывает много земли, поэтому он разделен на три части:

  • Как избежать CORS предполетного
  • как использовать прокси-сервер CORS, чтобы обойти "нет заголовка Access-Control-Allow-Origin" проблемы
  • как исправить "заголовок Access-Control-Allow-Origin не должен быть подстановочным знаком" проблемы

Как избежать CORS предполетного

код в вопросе запускается предварительный запуск CORS-так как он отправляет .

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_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 запросы. В этом случае другие серверы обычно отвечают кодом состояния 405 "метод не разрешен".

так что вы никогда не сможете сделать POST запрашивает непосредственно на этот сервер из вашего интерфейсного кода JavaScript, если сервер отвечает на это OPTIONS запрос с 405 или 501 или что-либо, кроме 200 или 204, или если не отвечает с этими необходимыми заголовками ответов.

путь к избегайте запуска предполетного режима для случая в вопросе:

  • если сервер не требует Authorization заголовок запроса, но вместо этого (например) полагался на данные аутентификации, встроенные в тело POST запрос или запрос с параметрами
  • если сервер не требует POST тело, чтобы иметь Content-Type: application/json тип носителя, но вместо этого принял POST тело application/x-www-form-urlencoded с параметром (или что-то еще) чье значение является JSON данные

как использовать прокси 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-адресом прокси-вызывает запрос на получение через этот прокси-сервер, который затем:

  1. перенаправляет запрос на https://example.com.
  2. получает ответ от https://example.com.
  3. добавляет Access-Control-Allow-Origin заголовок ответа.
  4. передает этот ответ с добавленным заголовком обратно в запрашивающий код интерфейса.

браузер затем позволяет интерфейсному коду получить доступ к ответу, потому что этот ответ с 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 или другой открытый прокси-сервер, это решение будет работать, даже если запрос является тем, который запускает браузеры, чтобы сделать CORS preflight OPTIONS request-потому что в этом случае прокси также отправляет обратно Access-Control-Allow-Headers и Access-Control-Allow-Methods заголовки, необходимые для успешной предполетной подготовки.


как исправить "заголовок 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 access control (CORS).

если вы управляете сервером вы отправляете запрос, то общий способ справиться с этим делом в настроить сервер, чтобы принять значение Origin заголовок запроса и Эхо / отражают это обратно в значение Access-Control-Allow-Origin заголовок ответа. Например, в nginx:

add_header Access-Control-Allow-Origin $http_origin

но это только один пример; другие (веб) серверные системы предоставляют аналогичные способы Эхо-значений происхождения.


я использую Chrome. Я также попытался использовать этот плагин Chrome CORS

что CORS хром плагин, видимо, просто simplemindedly впрыскивает Ан 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');

удалите эти строки. The Access-Control-Allow-* заголовки ответ заголовки. Вы никогда не хотите отправить их в запросе. Единственный эффект, который будет иметь, чтобы вызвать браузер, чтобы сделать предпечатную.


эта ошибка возникает, когда URL-адрес клиента и URL-адрес сервера не совпадают, включая номер порта. В этом случае вам нужно включить службу для CORS, которая является общим доступом к ресурсам cross origin.

Если вы размещаете сервис весеннего отдыха, вы можете найти его в блоге поддержка CORS в Spring Framework.

Если вы размещаете службу с помощью узла.сервер JS тогда

  1. остановить узел.Яш сервер.
  2. npm установить cors
  3. добавьте на сервер следующие строки.js

    var cors = require('cors')
    
    app.use(cors()) // Use this after the variable declaration
    

удалить этого:

credentials: 'include',

использовать тип данных: 'jsonp', работает для меня.

   async function get_ajax_data(){
       var _reprojected_lat_lng = await $.ajax({
                                type: 'GET',
                                dataType: 'jsonp',
                                data: {},
                                url: _reprojection_url,
                                error: function (jqXHR, textStatus, errorThrown) {
                                    console.log(jqXHR)
                                },
                                success: function (data) {
                                    console.log(data);

                                    // note: data is already json type, you just specify dataType: jsonp
                                    return data;
                                }
                            });


 } // function