Разрешить заголовок Access-Control-Allow-Origin с использованием HTML5 fetch API

87

Я использую HTML5 fetch API.

var request = new Request('https://davidwalsh.name/demo/arsenal.json');

fetch(request).then(function(response) {
    // Convert to JSON
    return response.json();
}).then(function(j) {
    // Yay, `j` is a JavaScript object
    console.log(JSON.stringify(j));
}).catch(function(error) {
    console.log('Request failed', error)
});

Я могу использовать обычный json, но не могу получить данные указанного выше URL-адреса api. Выдает ошибку:

API Fetch не может загрузить https://davidwalsh.name/demo/arsenal.json . На запрошенном ресурсе нет заголовка Access-Control-Allow-Origin. Следовательно, к источнику ' http: // localhost ' доступ запрещен. Если непрозрачный ответ соответствует вашим потребностям, установите режим запроса на 'no-cors', чтобы получить ресурс с отключенным CORS.

iNikkz
источник
Сторонний сервер должен установить его, вы ничего не можете сделать на стороне клиента.
epascarello
@epascarello: Мы можем делать это на стороне клиента. За кадром происходит запрос XHR. Пожалуйста, проверьте этоhttps://davidwalsh.name/fetch
iNikkz

Ответы:

81

Как сказал эпаскарелло, на сервере, на котором размещен ресурс, должен быть включен CORS. То, что вы можете сделать на стороне клиента (и, возможно, то, о чем вы думаете), - это установить режим выборки на CORS (хотя я считаю, что это настройка по умолчанию):

fetch(request, {mode: 'cors'});

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

Ознакомьтесь с документацией CORS и этим потрясающим видео Udacity, объясняющим политику одного и того же происхождения .

Вы также можете использовать режим no-cors на стороне клиента, но это просто даст вам непрозрачный ответ (вы не можете прочитать тело, но ответ все равно может быть кэширован работником службы или потреблен некоторыми API, например <img>) :

fetch(request, {mode: 'no-cors'})
.then(function(response) {
  console.log(response); 
}).catch(function(error) {  
  console.log('Request failed', error)  
});
Дэвид Скейлс
источник
2
Можете ли вы уточнить: «Однако для этого по-прежнему требуется, чтобы сервер также включил CORS и разрешил вашему домену запрашивать ресурс»? Я безуспешно искал инструкции для этого.
jayscript
2
@jayscript общий процесс выглядит так: на клиенте запрос на перекрестное происхождение выполняется с помощью javascript. В случае API выборки режим 'cors' сообщает браузеру, что он может сделать этот запрос. Если бы вместо этого у вас был режим «no-cors», браузер остановил бы запрос, потому что он не соответствует источнику вашего приложения. Сервер получит запрос и ответит. В браузере подтверждает , что ответ имеет соответствующие CORS заголовки, и если да, то позволяет ответ для чтения. Если заголовки отсутствуют, браузер выдаст ошибку.
Дэвид Скейлс
1
@jayscript эта статья MDN подробно описывает. По сути, на своем сервере вам нужно установить следующие заголовки: «Access-Control-Allow-Origin: foo.example », «Access-Control-Allow-Methods: POST, GET, OPTIONS», «Access-Control-Allow-Headers: X-PINGOTHER, Content-Type ", которые включают источники, методы и заголовки соответственно. Обычно для заголовка источника используется '*'. Вы также можете проверить этот документ Google и связанную с ним таблицу кодов, чтобы узнать о Fetch API: developers.google.com/web/ilt/pwa/working-with-the-fetch-api
David Scales
2
Спасибо! Это помогает мне понять, что невозможно получить данные с сервера API, имеющего другое происхождение, если сервер API не содержит заголовков. В конкретном случае, с которым я имел дело, у меня был доступ к коду сервера API и я мог самостоятельно добавлять заголовки, что позволяло получать данные.
jayscript
Это глупо, в чем проблема безопасности NO sendingфайлов cookie и, следовательно, разрешения CORS?
deathangel908
14

У меня был интерфейсный код, работающий на http: // localhost: 3000, а мой API (Backend code) работал на http: // localhost: 5000

Использовал API выборки для вызова API. Изначально выкидывал ошибку "корс". Затем добавил этот ниже код в мой код Backend API, разрешив источник и заголовок из любого места.

let allowCrossDomain = function(req, res, next) {
  res.header('Access-Control-Allow-Origin', "*");
  res.header('Access-Control-Allow-Headers', "*");
  next();
}
app.use(allowCrossDomain);

Однако вам следует ограничить ваше происхождение в случае других сред, таких как stage, prod.

смсивапракааш
источник
20
это ужасный ответ. это серьезная проблема безопасности. если вы читаете это, ПОЖАЛУЙСТА, НЕ ДЕЛАЙТЕ ЭТОГО.
mjones.udri
1
Это для локальной настройки. Например, чтобы сделать небольшую картинку. Да, существует угроза безопасности, если то же самое касается других развертываемых сред. Для местных я чувствую, что это не так. «Однако вы должны ограничить свое происхождение в случае других сред, таких как сцена, прод»
smsivaprakaash
12

Это сработало для меня:

npm install -g local-cors-proxy

Конечная точка API, которую мы хотим запросить, имеет проблемы с CORS:

https://www.yourdomain.com/test/list

Запустить прокси:

lcp --proxyUrl https://www.yourdomain.com

 Proxy Active 

 Proxy Url: http://www.yourdomain.com:28080
 Proxy Partial: proxy
 PORT: 8010

Затем в вашем клиентском коде новая конечная точка API:

http://localhost:8010/proxy/test/list

Конечным результатом будет запрос на https://www.yourdomain.ie/test/list без проблем с CORS!

ВигКам
источник
Pls убедитесь , что сервер работает параллельно , как открыть новые CMT-подсказки окна и запустить код LCP --proxyUrl yourdomain.com
Govarthanan Venunathan
8

Я знаю, что это более старый пост, но я обнаружил, что для исправления этой ошибки у меня сработало использование IP-адреса моего сервера вместо использования доменного имени в моем запросе на выборку. Так например:

#(original) var request = new Request('https://davidwalsh.name/demo/arsenal.json');
#use IP instead
var request = new Request('https://0.0.0.0/demo/arsenal.json');

fetch(request).then(function(response) {
    // Convert to JSON
    return response.json();
}).then(function(j) {
    // Yay, `j` is a JavaScript object
    console.log(JSON.stringify(j));
}).catch(function(error) {
    console.log('Request failed', error)
});
MattG
источник
1

Если вы используете nginx, попробуйте это

#Control-Allow-Origin access

    # Authorization headers aren't passed in CORS preflight (OPTIONS) calls. Always return a 200 for options.
    add_header Access-Control-Allow-Credentials "true" always;
    add_header Access-Control-Allow-Origin "https://URL-WHERE-ORIGIN-FROM-HERE " always;
    add_header Access-Control-Allow-Methods "GET,OPTIONS" always;
    add_header Access-Control-Allow-Headers "x-csrf-token,authorization,content-type,accept,origin,x-requested-with,access-control-allow-origin" always;

    if ($request_method = OPTIONS ) {
        return 200;
    }

Калиари
источник
-3

Посмотрите https://expressjs.com/en/resources/middleware/cors.html. Вы должны использовать cors.

Установить:

$ npm install cors
const cors = require('cors');
app.use(cors());

Вы должны поместить этот код на свой сервер узла.

Эрнерсто Пастори
источник
1
Как узнать, является ли это сервером OP, и он написан на NodeJs?
Марек Шкудельски
Если вы создали сервер узла (режим разработки), вы можете использовать этот метод для использования fetch в js.
Эрнерсто Пастори