Почему почтальон не получает сообщение об ошибке «Отсутствует заголовок Access-Control-Allow-Origin» на запрошенном ресурсе », когда мой код JavaScript появляется?


2503

Примечание для мода : Этот вопрос о том, почему Postman не подчиняется ограничениям CORS так же, как XMLHttpRequest. Этот вопрос не о том, как исправить ошибку "Нет 'Access-Control-Allow-Origin' ...".

Пожалуйста, прекратите публикацию :

  • Конфигурации CORS для каждого языка / фреймворка под солнцем. Вместо этого найдите вопрос вашего языка / основы .
  • Сторонние сервисы, позволяющие обойти запрос CORS
  • Параметры командной строки для отключения CORS для различных браузеров

Я пытаюсь выполнить авторизацию с помощью JavaScript , подключившись к RESTful API, встроенному в Flask . Однако, когда я делаю запрос, я получаю следующую ошибку:

XMLHttpRequest не может загрузить http: // myApiUrl / login . В запрошенном ресурсе отсутствует заголовок «Access-Control-Allow-Origin». Происхождение 'null', следовательно, не разрешено.

Я знаю, что API или удаленный ресурс должен устанавливать заголовок, но почему он работал, когда я делал запрос через расширение Chrome Postman ?

Это код запроса:

$.ajax({
    type: "POST",
    dataType: 'text',
    url: api,
    username: 'user',
    password: 'pass',
    crossDomain : true,
    xhrFields: {
        withCredentials: true
    }
})
    .done(function( data ) {
        console.log("done");
    })
    .fail( function(xhr, textStatus, errorThrown) {
        alert(xhr.responseText);
        alert(textStatus);
    });

32
Вы делаете запрос от localhost или прямо выполняете HTML?
доктор медицинских наук Сахиб бин Махбуб

@ MD.SahibBinMahboob Если я понимаю ваш вопрос, я запрашиваю у localhost - у меня есть страница на моем компьютере, и я просто запускаю ее. Когда я размещаю сайт на хостинге, он дает тот же результат.
г-н джедай

6
многое связано: stackoverflow.com/questions/10143093/…
cregox

8
Для тех, кто хочет больше читать, в MDN есть хорошая статья, посвященная ajax и запросам разных источников: developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Сэм Итон,

1
Одно важное замечание для этого типа ошибки в узле js. Вы ДОЛЖНЫ установить заголовки доступа при запуске файла server.js ДО начала настройки маршрутов. В противном случае все будет работать отлично, но вы получите эту ошибку, когда будете делать запросы из своего приложения.
Алекс Дж

Ответы:


1346

Если я правильно понял, вы делаете запрос XMLHttpRequest в другой домен, чем ваша страница. Поэтому браузер блокирует его, так как он обычно позволяет запрос в том же источнике по соображениям безопасности. Вам нужно сделать что-то другое, когда вы хотите сделать междоменный запрос. Учебник о том, как этого добиться, использует CORS .

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

Обычные веб-страницы могут использовать объект XMLHttpRequest для отправки и получения данных с удаленных серверов, но они ограничены одной и той же политикой происхождения. Расширения не так ограничены. Расширение может общаться с удаленными серверами за пределами своего источника, если оно сначала запрашивает разрешения между источниками.


7
Вы правы. Я делаю запрос на другой домен, чем моя страница. API находится на сервере, и я запускаю запрос от localhost. Прежде чем я приму ответ, вы можете объяснить, что означает «выполнение запроса напрямую»? POSTMAN не используете домен?
г-н джедай

181
Браузер не блокирует запрос. Единственные браузеры, которые напрямую блокируют запросы кросс-исходного кода Ajax, - это IE7 или старше. Все браузеры, кроме IE7 и более старых, реализуют спецификацию CORS (IE8 и IE9 частично). Все, что вам нужно сделать, это подписаться на запросы CORS на вашем сервере API, возвращая правильные заголовки на основе запроса. Вы должны прочитать о концепциях CORS на mzl.la/VOFrSz . Почтальон также отправляет запросы через XHR. Если вы не видите ту же проблему при использовании почтальона, это означает, что вы неосознанно не отправляете тот же запрос через почтальона.
Рэй Николай

10
@ MD.SahibBinMahboob Почтальон НЕ отправляет запрос "из вашего кода Java / Python". Это отправка запроса прямо из браузера. XHR в расширениях Chrome работает немного по-другому, особенно когда задействованы перекрестные запросы .
Рэй Николус

250

ВНИМАНИЕ: Использование Access-Control-Allow-Origin: *может сделать ваш API / веб-сайт уязвимым для атак подделки межсайтовых запросов (CSRF). Убедитесь, что вы понимаете риски, прежде чем использовать этот код.

Это очень просто решить, если вы используете PHP . Просто добавьте следующий скрипт в начало вашей PHP-страницы, которая обрабатывает запрос:

<?php header('Access-Control-Allow-Origin: *'); ?>

Если вы используете Node-red, вы должны разрешить CORS в node-red/settings.jsфайле, не комментируя следующие строки:

// The following property can be used to configure cross-origin resource sharing
// in the HTTP nodes.
// See https://github.com/troygoode/node-cors#configuration-options for
// details on its contents. The following is a basic permissive set of options:
httpNodeCors: {
 origin: "*",
 methods: "GET,PUT,POST,DELETE"
},

Если вы используете Flask так же, как вопрос; Вы должны сначала установитьflask-cors

$ pip install -U flask-cors

Затем включите флаконы в ваше приложение.

from flask_cors import CORS

Простое приложение будет выглядеть так:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"

Для более подробной информации, вы можете проверить документацию Flask .


93
и это не безопасно
llazzaro

153
Вы не должны выключать CORS, потому что не знаете, для чего это нужно. Это ужасный ответ.
Meagar

124
Хотя это может быть небезопасно, вопрос был не в безопасности, а в том, как выполнить задачу. Это одна из опций, которую разработчик должен выбрать при работе с междоменными запросами AJAX. Это помогло мне решить проблему, и для моего приложения мне все равно, откуда пришли данные. Я очищаю все входные данные с помощью PHP в целевом домене, поэтому, если кто-то захочет опубликовать на нем ненужную информацию, пусть попробуют. Суть в том, что междоменный AJAX может быть разрешен из конечного домена. +1 за ответ.
ZurabWeb

23
Хотя я согласен с общим посланием, которое дает Пьеро, речь идет не о безопасности, а о безопасности. Я думаю, что это должно было по крайней мере сказать что-то вроде: «Как правило, это плохо! Не делайте этого, если вы не знаете, что делаете! Вот еще документация по этому вопросу: ...», и, возможно, кратко объясните почему. Я бы не хотел, чтобы кто-то приходил сюда и думал: «О, я могу просто добавить / настроить этот заголовок, и я в порядке!» и не знаю всех последствий. Я имею в виду, это как бы их исследовать и все, но все же.
Томас Ф.

4
Мне нравится этот ответ ... У меня та же проблема, и она решает ее ... Он объяснил, что есть некоторые проблемы с безопасностью, но это еще одна проблема, и пусть каждый индивидуально подумает и решит эту проблему ...
Ари Вайсберг

64

Потому что
$ .ajax ({type: "POST" - вызывает OPTIONS
$ .post ( - вызывает POST

Оба разные. Почтальон правильно называет «POST», но когда мы его называем, это будут «OPTIONS».

Для веб-сервисов C # - веб-API

Добавьте следующий код в файл web.config под тегом <system.webServer>. Это будет работать:

<httpProtocol>
    <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
    </customHeaders>
</httpProtocol>

Пожалуйста, убедитесь, что вы не делаете никакой ошибки в вызове Ajax

JQuery

$.ajax({
    url: 'http://mysite.microsoft.sample.xyz.com/api/mycall',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    type: "POST", /* or type:"GET" or type:"PUT" */
    dataType: "json",
    data: {
    },
    success: function (result) {
        console.log(result);
    },
    error: function () {
        console.log("error");
    }
});

Примечание: Если вы ищете для загрузки контента с веб - сайта третьей стороной , то это не поможет . Вы можете попробовать следующий код, но не JavaScript.

System.Net.WebClient wc = new System.Net.WebClient();
string str = wc.DownloadString("http://mysite.microsoft.sample.xyz.com/api/mycall");

Этот конфиг решил ту же ошибку на Wordpress в Azure Services. Спасибо.
Андре Мескита

9
Я бы предложил использовать конкретное значение источника, чтобы избежать запросов от внешних доменов. Так например вместо *использованияhttps://www.myotherdomain.com
печар


8

Применение ограничения CORS - это функция безопасности, определяемая сервером и реализуемая браузером .

Браузер смотрит на политику сервера CORS и уважает ее.

Однако инструмент Postman не заботится о политике CORS сервера.

Вот почему ошибка CORS появляется в браузере, а не в Почтальоне.


1
Да, я не могу не подчеркнуть, почему эта маленькая деталь заслуживает некоторого внимания. Говоря о безопасности, необходимо упомянуть, что CORS настолько же силен, как и клиент, реализующий его. Итак, представьте, что вы берете простой HttpClient (серверный код) и создаете прокси-сервер, который затем выполняет ваши запросы ... Безопасность может быть полностью обойдена, действительно оставляя стандарт CORS плохим решением
Кристофер Бонитц

7

В приведенном ниже исследовании в качестве API я использую http://example.com вместо http: // myApiUrl / login из вашего вопроса, потому что этот первый работает.

Я предполагаю, что ваша страница находится на http: //my-site.local: 8088 .

Причина, по которой вы видите разные результаты, заключается в том, что почтальон:

  • установить заголовок Host=example.com(ваш API)
  • НЕ установить заголовок Origin

Это похоже на способ отправки запросов браузерами, когда сайт и API имеют одинаковый домен (браузеры также устанавливают элемент заголовка Referer=http://my-site.local:8088, однако я не вижу его в Postman). Когда Originзаголовок не установлен, обычно серверы разрешают такие запросы по умолчанию.

Введите описание изображения здесь

Это стандартный способ отправки запросов почтальоном. Но браузер отправляет запросы по-разному, когда ваш сайт и API имеют разные домены , а затем происходит CORS и браузер автоматически:

  • устанавливает заголовок Host=example.com(ваш как API)
  • устанавливает заголовок Origin=http://my-site.local:8088(ваш сайт)

(Заголовок Refererимеет то же значение, что и Origin). Теперь на вкладке « Консоль и сети » Chrome вы увидите:

Введите описание изображения здесь

Введите описание изображения здесь

Когда у вас есть Host != Originэто CORS, и когда сервер обнаруживает такой запрос, он обычно блокирует его по умолчанию .

Origin=nullустанавливается при открытии содержимого HTML из локального каталога и отправке запроса. Такая же ситуация возникает, когда вы отправляете запрос внутри <iframe>, как в следующем фрагменте кода (но здесь Hostзаголовок вообще не задан) - в общем, везде, где спецификация HTML говорит о непрозрачном происхождении, вы можете перевести это в Origin=null. Более подробную информацию об этом вы можете найти здесь .

fetch('http://example.com/api', {method: 'POST'});
Look on chrome-console > network tab

Если вы не используете простой запрос CORS, обычно браузер автоматически также отправляет запрос OPTIONS перед отправкой основного запроса - дополнительная информация здесь . Фрагмент ниже показывает это:

fetch('http://example.com/api', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json'}
});
Look in chrome-console -> network tab to 'api' request.
This is the OPTIONS request (the server does not allow sending a POST request)

Вы можете изменить конфигурацию вашего сервера, чтобы разрешать запросы CORS.

Вот пример конфигурации, которая включает CORS для nginx (файл nginx.conf) - будьте очень осторожны с настройками always/"$http_origin"для nginx и "*"для Apache - это разблокирует CORS из любого домена.

Вот пример конфигурации, которая включает CORS на Apache (файл .htaccess)


2

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

Вариант использования: в chrome при попытке вызвать конечную точку Spring REST в угловом формате.

введите описание изображения здесь

Решение: Добавьте аннотацию @CrossOrigin ("*") поверх соответствующего класса контроллера.

введите описание изображения здесь


Я использую localhost вместо * для безопасности
neo7bf

-1

Если вы используете .NET в качестве среднего уровня, четко проверьте атрибут маршрута, например,

У меня была проблема, когда это было так,

[Route("something/{somethingLong: long}")] //Space.

Исправлено этим,

[Route("something/{somethingLong:long}")] //No space

-1

Только для проекта .NET Core Web API добавьте следующие изменения:

  1. Добавьте следующий код после services.AddMvc()строки в ConfigureServices()методе файла Startup.cs:
services.AddCors(allowsites=>{allowsites.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
            });
  1. Добавьте следующий код после app.UseMvc()строки в Configure()метод файла Startup.cs:
app.UseCors(options => options.AllowAnyOrigin());
  1. Откройте контроллер, к которому вы хотите получить доступ за пределами домена, и добавьте следующий атрибут на уровне контроллера:
[EnableCors("AllowOrigin")]
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.