Чому листоноша не отримує заголовок "Ні" Access-Control-Allow-Origin "на запитуваному ресурсі", коли мій код JavaScript робить?


2500

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

Будь ласка, припиніть публікацію :

  • Конфігурації CORS для кожної мови / рамки під сонцем. Замість цього знайдіть відповідне питання щодо мови / рамки .
  • Сторонні послуги, які дозволяють запит обійти CORS
  • Параметри командного рядка для вимкнення CORS для різних браузерів

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

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?
д.м.н. Sahib Bin Mahboob

@ 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 перед тим, як розпочати налаштування маршрутів. Інакше все буде чудово, але ви отримаєте цю помилку, коли будете робити запити зі свого додатка.
Alex J

Відповіді:


1344

Якщо я зрозумів це правильно, ви робите 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 працює дещо інакше, особливо якщо це стосується запитів перехресного походження .
Рей Ніколаус

249

ПОПЕРЕДЖЕННЯ. Використання 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!"

Для отримання більш детальної інформації ви можете перевірити документацію на колбу .


93
і це не безпечно
llazzaro

153
Вам не слід вимикати CORS, оскільки ви не знаєте, для чого це потрібно. Це жахлива відповідь.
meagar

124
Незважаючи на те, що це може бути не безпечно, питання полягало не в безпеці, а в тому, як виконати завдання. Це один із варіантів, який розробник має вибрати, коли має справу з міждоменними запитами AJAX. Це допомогло мені вирішити проблему, і для моєї заявки мені все одно, звідки дані. Я переробляю весь вхід PHP на доменному пункті, тому, якщо хтось хоче розмістити на ньому якийсь небажаний, нехай він спробує. Тут головним є те, що міждоменний AJAX може бути дозволений з доменного пункту призначення. +1 для відповіді.
ZurabWeb

23
Хоча я погоджуюсь із загальним повідомленням, яке дає П'єро, що мова йде не лише про безпеку, але безпека викликає занепокоєння. Я думаю, що це повинно було хоча б сказати щось на кшталт "Це взагалі погано! Не робіть цього, якщо ви не знаєте, що ви робите! Ось додаткова документація на це: ...", і, можливо, коротко поясніть чому. Мені б не хотілося, щоб хтось сюди зайшов і просто подумав "О, я можу просто додати / відрегулювати цей заголовок, і мені добре!" і не знаю повних наслідків. Я маю на увазі, це щось на них для дослідження і все, але все ж.
Томас Ф.

4
Мені подобається ця відповідь ... У мене те саме питання, і воно вирішує ... Він пояснив, що є деякі проблеми безпеки, але це ще одна проблема, і нехай кожен індивідуально подумає і вирішить це питання ...
Арі Вайсберг

63

Тому що
$ .ajax ({тип: "POST" - викликає ОПЦІЇ
$ .post ( - Дзвінки POST)

Обидва різні. Листоноша належним чином називає "POST", але коли ми його зателефонуємо, це буде "OPTIONS".

Для веб-служб C # - Web 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
pechar


8

Застосування обмеження CORS - це функція безпеки, визначена сервером та реалізована браузером .

Браузер розглядає політику CORS сервера та поважає її.

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

Ось чому помилка CORS з’являється в браузері, але не в Postman.


1
Так, я не можу наголосити достатньо, чому ця маленька деталь заслуговує певної уваги. Говорячи про безпеку, перш за все слід зазначити, що CORS настільки ж сильний, як і клієнт, який реалізує це. Тож уявіть, що ви берете простий HttpClient (код на стороні сервера) і будуєте проксі-сервер, який потім виконує ваші запити ...
Безпеку

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

Зустрічалася однакова помилка в різних випадках використання.

Використовуйте випадок: У хромі, коли намагалися зателефонувати до кінцевої точки 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.