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

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

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

Fetch API не может загрузить . Ответ на запрос preflight не проходит прошел проверку контроля доступа: No 'Access-Control-Allow-Origin' header is присутствует на запрашиваемом ресурсе. Origin 'http://127.0.0.1:3000' является поэтому доступ к нему запрещен. Ответ имеет код состояния 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 Plugin, но тогда я получаю другое сообщение об ошибке:

Значение заголовка 'Access-Control-Allow-Origin' в ответе не должно быть подстановочным символом '*', когда запрос'credentials mode is 'include'. Таким образом, Origin 'http://127.0.0.1:3000' не имеет права доступ. Режим учетных данных для запросов, инициированных функцией XMLHttpRequest, контролируется атрибутом withCredentials.

Решение

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

  • Как использовать 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-by, просто префиксировав его с 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/. Тогда вместо префикса 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 или другой открытый прокси, это решение будет работать, даже если запрос будет таким, который заставляет браузеры делать предварительный CORS-запрос OPTIONS - потому что в этом случае прокси также отправляет обратно заголовки 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 также вызовет префлайт. Что означает "preflight": прежде чем браузер попробует выполнить 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, замененным на ваш фактический URL sign_in. Ответ, который браузер должен получить от этого запроса 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' в ответе не должно быть подстановочным символом '', когда запрос'режим учетных данных является 'include'. Таким образом, Origin 'http://127.0.0.1:3000' не разрешается. доступ. Режим учетных данных для запросов, инициированных XMLHttpRequest, контролируется атрибутом withCredentials. Для запроса, содержащего учетные данные, браузеры не позволят вашему фронтенд-коду JavaScript получить доступ к ответу, если значение заголовка ответа Access-Control-Allow-Origin равно `. Вместо этого значение в этом случае должно точно соответствовать происхождению вашего внешнего кода,http://127.0.0.1:3000. Смотрите [*Кредитные запросы и подстановочные знаки*][1] в статье MDN HTTP контроль доступа (CORS). Если вы контролируете сервер, на который отправляете запрос, то распространенным способом решения этой проблемы является настройка сервера на получение значения заголовка запросаOriginи его эхо/отражение в значение заголовка ответаAccess-Control-Allow-Origin`. Например, в nginx:

add_header Access-Control-Allow-Origin $http_origin

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

Я использую Chrome. Я также пробовал использовать этот Chrome CORS Plugin. Этот CORS-плагин Chrome, по-видимому, просто-напросто вводит 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-* являются заголовками ответа. Вы никогда не захотите отправлять их в запросе. Единственное, на что это может повлиять, - заставить браузер выполнить предварительную проверку.

Комментарии (8)

Эта ошибка возникает, когда URL клиента и URL сервера не совпадают, включая номер порта. В этом случае вам необходимо включить в вашем сервисе функцию CORS - кросс-оригинальный обмен ресурсами.

Если вы используете REST-сервис Spring, то вы можете найти это в блоге Поддержка CORS в Spring Framework.

Если вы размещаете сервис на сервере Node.js, то

  1. Остановите сервер Node.js.

  2. npm install cors --save.

  3. Добавьте следующие строки в файл server.js

    var cors = require('cors')

    app.use(cors()) // Используйте это после объявления переменной

Комментарии (4)

Проблема возникла из-за того, что вы добавили следующий код в виде заголовка request в интерфейсе:

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

Эти заголовки принадлежат ответу , а не запросу. Так что удалите их, включая строку: < br / >

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

Ваш запрос имел «Content-Type: application / json», следовательно, вызвал то, что называется предполетным CORS. Это вызвало то, что браузер отправил запрос с методом OPTIONS. См. CORS preflight для получения подробной информации. & Лт; br / > Поэтому в вашем бэк-энде вы должны обработать этот предварительно выполненный запрос, вернув заголовки ответов, которые включают:

Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept

Конечно, фактический синтаксис зависит от языка программирования, который вы используете для своего бэкэнда.

В вашем интерфейсе это должно быть так:

function performSignIn() {
    let headers = new Headers();

    headers.append('Content-Type', 'application/json');
    headers.append('Accept', 'application/json');
    headers.append('Authorization', 'Basic ' + base64.encode(username + ":" +  password));
    headers.append('Origin','http://localhost:3000');

    fetch(sign_in, {
        mode: 'cors',
        credentials: 'include',
        method: 'POST',
        headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}
Комментарии (1)

В моем случае я использую решение ниже

Front-end или Angular

post(
    this.serverUrl, dataObjToPost,
    {
      headers: new HttpHeaders({
           'Content-Type':  'application/json',
         })
    }
)

бэкэнд (я использую php)

header("Access-Control-Allow-Origin: http://localhost:4200");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header("Access-Control-Allow-Headers: Content-Type, Authorization");

$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r($request);
Комментарии (0)

Просто мои два цента... относительно Как использовать прокси-сервер CORS, чтобы обойти проблемы «Нет заголовка« Access-Control-Allow-Origin »

Для тех из вас, кто работает с php на бэкэнде, развертывание «прокси-сервера CORS» так же просто, как:

  1. создать файл с именем 'no-cors.php' со следующим содержимым:

    $ URL = $ _GET ['url'] ; echo json_encode (file_get_contents ($ URL)) ; умереть();

  2. на переднем конце сделайте что-нибудь вроде:

    fetch ('https://example.com/no-cors.php' + '?url = '+ url) .then (response = > {* / Handle Response / *})

Комментарии (1)

Уберите это:

credentials: 'include',
Комментарии (0)

В моем случае веб-сервер предотвратил метод «ОПЦИИ»

Проверьте свой веб-сервер на предмет параметров метода

Я использую "вебтиер"

/www / webtier / домены / [доменное имя] /config/fmwconfig/components / OHS / VCWeb1 / httpd.conf


  RewriteEngine on
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]

перейти на


  RewriteEngine off
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]
Комментарии (0)

Я получал эту ошибку на моем местном. Я запустил Visual Studio в качестве администратора, и это решено.

Комментарии (0)

Использование dataType: '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               
Комментарии (0)

Я работал с Spring REST и решил добавить «Разрешенные методы» в WebMvcConfigurer.

@Value( "${app.allow.origins}" )
    private String allowOrigins;    
@Bean
public WebMvcConfigurer corsConfigurer() {
            System.out.println("allow origin: "+allowOrigins);
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")
                    //.allowedOrigins("http://localhost")
                    .allowedOrigins(allowOrigins)
                    .allowedMethods("PUT", "DELETE","GET", "POST");
                }
            };
        }
Комментарии (0)

Самое быстрое исправление, которое вы можете сделать, - это установить расширение Moesif CORS .

https://chrome.google.com/webstore/detail/moesif-orign-cors-changer/digfbfaphojjndkpccljibejjbppifbc?hl=en-US

После установки щелкните его в браузере, чтобы активировать расширение. Убедитесь, что метка значка идет от «выкл» «вкл» ; Затем обновите ваше приложение, и ваши запросы API теперь должны работать! Плагин определенно решает проблему. Однако это исправление относится только к вашей машине. В локальном развитии хорошо установить плагин, который поможет вам преодолеть ошибку.

Комментарии (0)