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


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

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

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

Я понимаю, что это потому, что я пытаюсь извлечь эти данные из моего локального хоста, и решение должно использовать 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 132

4 ответа:

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

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

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

код в вопросе триггеры CORS preflight-так как он отправляет .

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 запрос-потому что в этом случае, прокси-сервер также отправляет обратно 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

этот плагин 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-* заголовки ответ заголовки. Вы никогда не хотите, чтобы отправить их в запрос. Единственный эффект, который будет иметь это вызвать браузер, чтобы сделать предполетный.

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

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

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

  1. остановить узел.js сервер.
  2. npm install 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