Почему почтальон не получает сообщение об ошибке «Отсутствует заголовок 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.