Попытка использовать выборку и передачу в режиме: no-cors

Я могу попасть в эту конечную точку http://catfacts-api.appspot.com/api/facts?number=99 через Postman, и она вернет JSON

Кроме того, я использую приложение create-response-app и не хочу настраивать конфигурацию сервера.

В моем клиентском коде я пытаюсь использовать fetch, чтобы сделать то же самое, но получаю сообщение об ошибке:

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

Итак, я пытаюсь передать объект в свой Fetch, который отключит CORS, например:

fetch('http://catfacts-api.appspot.com/api/facts?number=99', { mode: 'no-cors'})
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });

Что интересно, полученная мной ошибка на самом деле является синтаксической ошибкой этой функции. Я не уверен, что мой реальный fetch сломан, потому что, когда я удаляю объект {mode: 'no-cors'} и предоставляю ему другой URL-адрес, он работает нормально.

Я также пытался передать объект { mode: 'opaque'}, но это возвращает исходную ошибку сверху.

Я верю, что все, что мне нужно сделать, это отключить CORS. Что мне не хватает?


person dwww    schedule 06.04.2017    source источник
comment
Отвечает ли это на ваш вопрос? Обработка ответа - SyntaxError: неожиданный конец ввод при использовании режима: 'no-cors'   -  person Cees Timmerman    schedule 20.11.2020


Ответы (7)


mode: 'no-cors' волшебным образом не заставит все работать. На самом деле это только усугубляет ситуацию, потому что одним из следствий этого является указание браузерам: «Запретить моему внешнему JavaScript-коду просматривать содержимое тела и заголовков ответа при любых обстоятельствах». Конечно, вы почти никогда не хочу это.

Что происходит с запросами из разных источников из внешнего интерфейса JavaScript, так это то, что браузеры по умолчанию блокируют доступ кода внешнего интерфейса к ресурсам из разных источников. Если Access-Control-Allow-Origin находится в ответе, браузеры ослабят эту блокировку и позволят вашему коду получить доступ к ответу.

Но если сайт не отправляет Access-Control-Allow-Origin в своих ответах, ваш интерфейсный код не может напрямую получить доступ к ответам с этого сайта. В частности, вы не можете исправить это, указав mode: 'no-cors' (фактически, это гарантирует, что ваш код внешнего интерфейса не сможет получить доступ к содержимому ответа).

Однако одна вещь, которая будет работать: если вы отправите свой запрос через прокси CORS.

Вы также можете легко развернуть собственный прокси на 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/.

Префикс URL-адреса вашего запроса с URL-адресом вашего прокси-сервера; Например:

https://cryptic-headland-94862.herokuapp.com/https://example.com

Добавление URL-адреса прокси в качестве префикса приводит к тому, что запрос выполняется через ваш прокси, который затем:

  1. Перенаправляет запрос на https://example.com.
  2. Получает ответ от https://example.com.
  3. Добавляет заголовок Access-Control-Allow-Origin к ответу.
  4. Передает этот ответ с добавленным заголовком обратно запрашивающему коду внешнего интерфейса.

Затем браузер позволяет коду внешнего интерфейса получить доступ к ответу, потому что этот ответ с заголовком ответа Access-Control-Allow-Origin - это то, что браузер видит.

Это работает, даже если это запрос, который заставляет браузеры выполнять предварительный OPTIONS запрос CORS, потому что в этом случае прокси также отправляет обратно заголовки Access-Control-Allow-Headers и Access-Control-Allow-Methods, необходимые для успешной предварительной проверки.


Я могу попасть в эту конечную точку http://catfacts-api.appspot.com/api/facts?number=99 через Postman

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS объясняет, почему даже если вы можете получить доступ к ответу с помощью Postman, браузеры не позволят вам получить доступ к ответу из разных источников из внешнего кода JavaScript, запущенного в веб-приложении, если ответ не содержит Access-Control-Allow-Origin заголовок ответа.

http://catfacts-api.appspot.com/api/facts?number=99 не имеет Access-Control-Allow-Origin заголовка ответа, поэтому код внешнего интерфейса не может получить доступ к ответу из разных источников.

Ваш браузер может получить ответ нормально, и вы можете увидеть его в Postman и даже в инструментах разработчика браузера, но это не значит, что браузеры будут предоставлять его вашему коду. Не получат, потому что у него нет Access-Control-Allow-Origin заголовка ответа. Поэтому вместо этого вы должны использовать прокси, чтобы получить его.

Прокси-сервер отправляет запрос на этот сайт, получает ответ, добавляет заголовок ответа Access-Control-Allow-Origin и любые другие необходимые заголовки CORS, а затем передает его обратно в ваш запрашивающий код. И этот ответ с добавленным заголовком Access-Control-Allow-Origin - это то, что видит браузер, поэтому браузер позволяет вашему коду внешнего интерфейса фактически получать доступ к ответу.


Итак, я пытаюсь передать объект в свой Fetch, который отключит CORS.

Ты не хочешь этого делать. Для ясности: когда вы говорите, что хотите «отключить CORS», кажется, вы на самом деле имеете в виду, что хотите отключить политика одного и того же происхождения. На самом деле CORS - это способ сделать это - CORS - это способ ослабить политику одного и того же происхождения, а не способ ее ограничить.

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

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

Скорее всего, вы никогда не захотите использовать mode: 'no-cors' на практике, за исключением нескольких ограниченных случаев, и даже тогда, только если вы точно знаете, что делаете и каковы эффекты. Это потому, что параметр mode: 'no-cors' на самом деле говорит браузеру: «Запретить моему внешнему JavaScript-коду просматривать содержимое тела и заголовков ответа при любых обстоятельствах». В большинстве случаев это явно не то, что вам нужно. хотеть.


Что касается случаев, когда вы хотели бы рассмотреть возможность использования mode: 'no-cors', см. Ответ на странице Какие ограничения применяются к непрозрачным ответам? для получения подробной информации. Суть в том, что кейсы:

  • В ограниченном случае, когда вы используете JavaScript для помещения содержимого из другого источника в элемент <script>, <link rel=stylesheet>, <img>, <video>, <audio>, <object>, <embed> или <iframe> (который работает, потому что для них разрешено встраивание ресурсов из другого источника) - но по какой-то причине вы не хотите или не можете этого сделать, просто используя в разметке документа URL-адрес ресурса в качестве атрибута href или src для элемента.

  • Когда единственное, что вы хотите сделать с ресурсом, - это кэшировать его. Как указано в ответе Какие ограничения применяются к непрозрачным ответам?, на практике сценарий, который применяется, - это когда вы используете Service Workers, и в этом случае релевантным API является Cache Storage API.

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


Я также пытался передать объект { mode: 'opaque'}

Режима запроса mode: 'opaque' отсутствует - opaque вместо этого является просто свойством ответа, и браузеры устанавливают это свойство непрозрачности для ответов на запросы, отправленные в режиме no-cors.

Но, кстати, слово непрозрачный является довольно явным сигналом о природе ответа, который вы получите: «непрозрачный» означает, что вы его не видите.

person sideshowbarker    schedule 07.04.2017
comment
Нравится cors-anywhere обходной путь для простых случаев использования, не связанных с производством (например, получение некоторых общедоступных данных). Этот ответ подтверждает мое подозрение, что no-cors встречается нечасто, потому что его OpaqueResponse не очень полезен; т.е. очень ограниченные случаи; может ли кто-нибудь объяснить мне примеры, где no-cors пригодится? - person The Red Pea; 29.09.2018
comment
@TheRedPea См. Обновление, которое я внес в ответ здесь (и это я также добавил в качестве комментариев к вашему вопросу на stackoverflow.com/questions/52569895/) - person sideshowbarker; 30.09.2018
comment
Мне нужно было настроить свой сервер Express с помощью пакета CORS.js - github.com/expressjs/cors - а затем мне нужно было удалить mode: 'no-cors' из запроса на выборку (иначе ответ был бы пустым) - person James L.; 09.11.2018
comment
прокси CORS великолепен. Я поражен тем, что вообще блокирование доступа к публичным файлам считается мерой безопасности. С точки зрения хакера, это так легко обойтись, и это именно то, что он делает. Для хороших актеров это просто хлопот. - person Seph Reed; 02.10.2019
comment
Я генерирую код разных клиентов, использующих один и тот же API. Использую для тренировок. Я хочу, чтобы код был простым и позволял пользователям играть с ним. Мне нужно использовать без креста. - person profimedica; 01.12.2019
comment
Это отличное решение, за исключением того, что мне нужно сделать - узнать страну посетителя, позвонив в службу, которая это делает. Если запрос проходит через прокси, я просто получаю страну прокси-сервера для всех. Есть другие идеи? Это должно быть бесплатно и должно работать на странице Netlify, обслуживаемой https. - person Dan Cancro; 07.07.2020
comment
Ничего. Разобрался, как работает jsonp. w3schools.com/js/js_json_jsonp.asp - person Dan Cancro; 07.07.2020
comment
Это действительно глупое сообщение об ошибке от Chrome: доступ для загрузки на 'quake.okayfun.com /maps/baseq3/index.json 'from origin' localhost: 8080 'заблокирован политикой CORS : Заголовок Access-Control-Allow-Origin отсутствует в запрошенном ресурсе. Если непрозрачный ответ соответствует вашим потребностям, установите режим запроса на 'no-cors', чтобы получить ресурс с отключенным CORS. - person Megamind; 23.12.2020
comment
Непрозрачность заставляет меня думать: нет, мы не будем запускать Javascript или отправлять файлы cookie или учетные данные, но вы все равно можете читать контент - person Megamind; 23.12.2020
comment
«Запретить моему внешнему JavaScript-коду просматривать содержимое тела ответа и заголовков при любых обстоятельствах». - какое краткое изложение очевидно бесполезной функции. Спасибо, что объяснили это так ясно, как это; Я сходил с ума, пытаясь понять, для чего он служит ... - person JamesTheAwesomeDude; 03.03.2021

Итак, если вы, как и я, разрабатываете веб-сайт на localhost, где вы пытаетесь получить данные из Laravel API и использовать их в своем интерфейсе Vue, и вы видите эту проблему, вот как я ее решил:

  1. В своем проекте Laravel запустите команду php artisan make:middleware Cors. Это создаст для вас app/Http/Middleware/Cors.php.
  2. Добавьте следующий код в функцию handles в Cors.php:

    return $next($request)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    
  3. В app/Http/kernel.php добавьте следующую запись в массив $routeMiddleware:

    ‘cors’ => \App\Http\Middleware\Cors::class
    

    (В массиве будут другие записи, такие как auth, guest и т. Д. Также убедитесь, что вы делаете это в app/Http/kernel.php, потому что в Laravel есть еще один kernel.php)

  4. Добавьте это промежуточное ПО при регистрации маршрута для всех маршрутов, к которым вы хотите разрешить доступ, например:

    Route::group(['middleware' => 'cors'], function () {
        Route::get('getData', 'v1\MyController@getData');
        Route::get('getData2', 'v1\MyController@getData2');
    });
    
  5. В интерфейсе Vue убедитесь, что вы вызываете этот API в mounted() функции, а не в data(). Также убедитесь, что вы используете http:// или https:// с URL-адресом в вашем fetch() вызове.

Полное описание статьи в блоге Пита Хьюстона.

person dotNET    schedule 17.07.2019

Если вы используете Express в качестве серверной части, вам просто нужно установить cors, импортировать и использовать его в app.use (cors ()) ;. Если проблема не устранена, попробуйте переключить порты. Это обязательно исчезнет после переключения портов

person Varnit Rohilla    schedule 23.08.2020
comment
Я помню, как я учился в старших классах колледжа, и никакие другие группы не работали с этим, кроме нашей - как ни странно, это простое решение. Вот более подробное руководство: stackabuse.com/handling-cors-with-node-js - person velkoon; 14.05.2021

Решение для меня заключалось в том, чтобы просто сделать это на стороне сервера

Я использовал библиотеку C # WebClient, чтобы получить данные (в моем случае это были данные изображения) и отправить их обратно клиенту. Вероятно, есть что-то очень похожее на выбранном вами серверном языке.

//Server side, api controller

[Route("api/ItemImage/GetItemImageFromURL")]
public IActionResult GetItemImageFromURL([FromQuery] string url)
{
    ItemImage image = new ItemImage();

    using(WebClient client = new WebClient()){

        image.Bytes = client.DownloadData(url);

        return Ok(image);
    }
}

Вы можете настроить его в соответствии с вашим собственным вариантом использования. Главное, чтобы client.DownloadData() работал без ошибок CORS. Обычно проблемы CORS возникают только между веб-сайтами, поэтому можно делать «межсайтовые» запросы с вашего сервера.

Тогда вызов React fetch так же прост, как:

//React component

fetch(`api/ItemImage/GetItemImageFromURL?url=${imageURL}`, {            
        method: 'GET',
    })
    .then(resp => resp.json() as Promise<ItemImage>)
    .then(imgResponse => {

       // Do more stuff....
    )}
person Stuart Aitken    schedule 23.12.2018

Очень простое решение (2 минуты на настройку) - использовать local-ssl-proxy пакет от npm

Использование довольно простое:
1. Установите пакет: npm install -g local-ssl-proxy
2. Во время работы local-server замаскируйте его с помощью local-ssl-proxy --source 9001 --target 9000

P.S: замените --target 9000 на -- "number of your port" и --source 9001 на --source "number of your port +1"

person volna    schedule 27.01.2019
comment
У меня проблема с использованием моего приложения на реальном телефоне. Ваше решение полезно в этом случае? - person Hamid Araghi; 18.07.2019
comment
@HamidAraghi Я бы предположил, что сейчас, поскольку для целей разработки прокси-сервер должен работать на устройстве, на которое фактически повлияла ошибка - person volna; 19.07.2019

Простое решение: добавьте следующее в самый верх php-файла, из которого вы запрашиваете данные.

header("Access-Control-Allow-Origin: *");
person Really Nice Code    schedule 12.04.2019
comment
Это очень хорошая идея, если вы хотите минимально возможную безопасность :). - person Heretic Monkey; 11.11.2019
comment
Отличная идея, если вы контролируете источник. - person baash05; 21.02.2021
comment
Ужасная идея. Во-первых, он работает только в том случае, если у вас есть доступ к источнику, чего нет у OP, и вам следует делать это только в том случае, если вы знаете о последствиях для безопасности. - person Guntram Blohm; 12.04.2021

Если все вышеперечисленные решения не работают, возможно, это из-за прав доступа к файлам, так как иногда, даже если вы исправили проблему, не связанную с cors, с помощью Heroku или другим способом, она выдает ошибку 403 запрещено. Установите права доступа к каталогу / файлу следующим образом:

Ошибки разрешений и владения Ошибка 403 Запрещено также может быть вызвана неправильным владением или разрешениями для файлов и папок вашего веб-содержимого.

Разрешения Эмпирическое правило для правильных разрешений:

Папки: 755

Статическое содержимое: 644

Динамическое содержание: 700

person NAVNEET CHANDAN    schedule 25.06.2021