Почему отправляется запрос OPTIONS и могу ли я его отключить?

Я строю веб-API. Я обнаружил, что всякий раз, когда я использую Chrome для POST, GET для моего API, всегда есть запрос OPTIONS, отправляемый перед реальным запросом, что довольно раздражает. В настоящее время я получаю сервер игнорировать любые запросы OPTIONS. Теперь мои вопросы: что хорошего в отправке запроса OPTIONS для удвоения нагрузки на сервер? Есть ли способ полностью запретить браузеру отправлять запросы OPTIONS?

Ответ 1

edit 2018-09-13: добавлены некоторые уточнения в отношении этого запроса перед полетом и как его избежать в конце этого ответа.

Запросы OPTIONS - это то, что мы называем pre-flight запросами при Cross-origin resource sharing (CORS).

Они необходимы, когда вы делаете запросы из разных источников в определенных ситуациях.

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

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

Хороший ресурс можно найти здесь http://enable-cors.org/

Чтобы справиться с этим, чтобы убедиться, что для любого пути с методом OPTIONS сервер отправляет ответ с этим заголовком

Access-Control-Allow-Origin: *

Это скажет браузеру, что сервер готов отвечать на запросы любого происхождения.

Для получения дополнительной информации о том, как добавить поддержку CORS на ваш сервер, смотрите следующую блок-схему

http://www.html5rocks.com/static/images/cors_server_flowchart.png

CORS Flowchart


редактировать 2018-09-13

Запрос CORS OPTIONS запускается только в некоторых случаях, как объяснено в документах MDN:

Некоторые запросы не запускают предварительную проверку CORS. В этой статье они называются "простыми запросами", хотя в спецификации Fetch (которая определяет CORS) этот термин не используется. Запрос, который не запускает предварительную проверку CORS - так называемый "простой запрос" - это запрос, который удовлетворяет всем следующим условиям:

Единственные допустимые методы:

  • ПОЛУЧИТЬ
  • ГОЛОВА
  • СООБЩЕНИЕ

Помимо заголовков, автоматически устанавливаемых пользовательским агентом (например, Connection, User-Agent или любым другим заголовком с именами, определенными в спецификации Fetch как "имя запрещенного заголовка"), единственными заголовками, которым разрешено быть вручную устанавливаются те, которые спецификация Fetch определяет как "заголовок запроса CORS-safelisted", а именно:

  • принимать
  • Accept-Language
  • Content-Language
  • Content-Type (но обратите внимание на дополнительные требования ниже)
  • DPR
  • Downlink
  • Сохранить данные
  • ВЭкран-Ширина
  • ширина

Единственные допустимые значения для заголовка Content-Type:

  • применение/х-WWW-форм-urlencoded
  • многочастному/форм-данных,
  • текст/обычный

Ни один прослушиватель событий не зарегистрирован ни для какого объекта XMLHttpRequestUpload, используемого в запросе; доступ к ним осуществляется с помощью свойства XMLHttpRequest.upload.

В запросе не используется объект ReadableStream.

Ответ 2

Прошел эту проблему, ниже мое заключение к этой проблеме и мое решение.

В соответствии со стратегией CORS (настоятельно рекомендуем вам прочитать об этом) Вы не можете просто заставить браузер прекратить отправку запроса OPTIONS, если он сочтет это необходимым.

Есть два способа обойти это:

  1. Убедитесь, что ваш запрос является "простым запросом"
  2. Установите Access-Control-Max-Age для запроса OPTIONS

Простой запрос

Простой межсайтовый запрос - это тот, который удовлетворяет всем следующим условиям:

Единственные допустимые методы:

  • ПОЛУЧИТЬ
  • ГОЛОВА
  • СООБЩЕНИЕ

Помимо заголовков, автоматически устанавливаемых пользовательским агентом (например, Connection, User-Agent и т.д.), Единственными заголовками, которые разрешено устанавливать вручную, являются:

  • принимать
  • Accept-Language
  • Content-Language
  • Тип содержимого

Единственные допустимые значения для заголовка Content-Type:

  • применение/х-WWW-форм-urlencoded
  • многочастному/форм-данных,
  • текст/обычный

Простой запрос не вызовет предполетный запрос ОПЦИИ.

Установить кеш для проверки ОПЦИИ

Вы можете установить Access-Control-Max-Age для запроса OPTIONS, чтобы он не проверял разрешение снова, пока не истечет срок его действия.

Access-Control-Max-Age дает значение в секундах, в течение которого можно кэшировать ответ на запрос предварительной проверки без отправки другого запроса предварительной проверки.

Ограничение отмечено

  • Для Chrome максимальное количество секунд для Access-Control-Max-Age составляет 600 что составляет 10 минут, согласно исходному коду Chrome.
  • Access-Control-Max-Age работает только для одного ресурса каждый раз, например, запросы GET с одинаковым URL-путем, но разные запросы будут обрабатываться как разные ресурсы. Таким образом, запрос ко второму ресурсу будет по-прежнему вызывать предварительный запрос.

Ответ 3

Пожалуйста, обратитесь к этому ответу о фактической потребности в запросах предоплаченных ВАРИАНТОВ: CORS - Какова мотивация внедрения предполетных запросов?

Чтобы отключить запрос OPTIONS, ниже для выполнения ajax-запроса должны быть выполнены условия:

  • Запрос не устанавливает пользовательские заголовки HTTP, такие как "application/xml" или "application/json" и т.д.
  • Метод запроса должен быть одним из GET, HEAD или POST. Если POST, тип содержимого должен быть одним из application/x-www-form-urlencoded, multipart/form-data или text/plain

Ссылка: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Ответ 4

Когда вы открываете консоль отладки и включен параметр " Disable Cache, запросы предварительной проверки всегда будут отправляться (т.е. Перед каждым запросом). если вы не отключите кеш, запрос перед полетом будет отправлен только один раз (на сервер)

Ответ 5

Да, можно избежать опций запроса. Запрос параметров - это предварительный запрос при отправке (публикации) любых данных в другой домен. Это проблема безопасности браузера. Но мы можем использовать другую технологию: транспортный слой iframe. Я настоятельно рекомендую вам забыть о любой конфигурации CORS и использовать готовое решение, и оно будет работать где угодно.

Посмотрите здесь: https://github.com/jpillora/xdomain

И рабочий пример: http://jpillora.com/xdomain/

Ответ 6

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

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

Ответ 7

Для разработчика, который понимает причину, по которой он существует, но ему необходимо получить доступ к API, который не обрабатывает вызовы OPTIONS без авторизации, мне нужен временный ответ, чтобы я мог развиваться локально, пока владелец API не добавит надлежащую поддержку SPA CORS или я не получу API прокси-сервера.

Я обнаружил, что вы можете отключить CORS в Safari и Chrome на Mac.

Отключить такую ​​же политику происхождения в Chrome

Chrome: закройте Chrome, откройте терминал и вставьте следующую команду: open /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir

Safari: Отключение политики одного и того же происхождения в Safari

Если вы хотите отключить политику одного и того же происхождения в Safari (у меня есть 9.1.1), вам нужно только включить меню разработчика и выбрать "Отключить ограничения перекрестного происхождения" в меню разработки.

Ответ 8

Я решил эту проблему как.

if($_SERVER['REQUEST_METHOD'] == 'OPTIONS' && ENV == 'devel') {
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Headers: X-Requested-With');
    header("HTTP/1.1 200 OK");
    die();
}

Это только для развития. При этом я жду 9 мс и 500 мс, а не 8 и 500 мс. Я могу это сделать, потому что производственное приложение JS будет находиться на той же машине, что и на производстве, поэтому не будет OPTIONS, но разработка - моя локальная.

Ответ 9

Вы не можете, но вы можете избежать использования CORS с помощью JSONP.

Ответ 10

Проведя целую полтора дня, пытаясь справиться с подобной проблемой, я обнаружил, что это связано с IIS.

Проект Web API был настроен следующим образом:

// WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
    var cors = new EnableCorsAttribute("*", "*", "*");
    config.EnableCors(cors);
    //...
}

У меня не было определенных параметров конфигурации CORS в узле web.config> system.webServer, как я видел во многих сообщениях

Нет специального кода CORS в global.asax или в контроллере в качестве декоратора

Проблема была в настройках пула приложений.

Режим управляемого конвейера был настроен на классический (сменил его на интегрированный), а Identity была установлена на Network Service (сменила его на ApplicationPoolIdentity)

Изменение этих настроек (и обновление пула приложений) исправило это для меня.

Ответ 11

Что сработало для меня, было импортировать "github.com/gorilla/handlers", а затем использовать его следующим образом:

router := mux.NewRouter()
router.HandleFunc("/config", getConfig).Methods("GET")
router.HandleFunc("/config/emcServer", createEmcServers).Methods("POST")

headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type"})
originsOk := handlers.AllowedOrigins([]string{"*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})

log.Fatal(http.ListenAndServe(":" + webServicePort, handlers.CORS(originsOk, headersOk, methodsOk)(router)))

Как только я выполнил запрос POJ Ajax и связал с ним данные JSON, Chrome всегда будет добавлять заголовок Content-Type, который не был в моей предыдущей конфигурации AllowedHeaders.

Ответ 12

Я думаю, вы отправляете запрос на перекрестный домен.

Для междоменных запросов установка типа содержимого для чего-либо, кроме приложения /x-www-form-urlencoded, multipart/form-data или text/plain, приведет к тому, что браузер отправит на сервер запрос предварительной проверки OPTIONS.

Поэтому вам может потребоваться указать contentType, чтобы избежать запроса OPTION.

Пример JQuery:

$.ajax({
    url: "http://crossdomainurl",
    type: "POST",
    contentType: 'text/plain'
}); 

Ответ 13

Одно из решений, которое я использовал в прошлом - скажем, что ваш сайт находится на mydomain.com, и вам нужно сделать запрос ajax для foreigndomain.com

Настройте переписку IIS из своего домена в чужой домен.

<rewrite>
  <rules>
    <rule name="ForeignRewrite" stopProcessing="true">
        <match url="^api/v1/(.*)$" />
        <action type="Rewrite" url="https://foreigndomain.com/{R:1}" />
    </rule>
  </rules>
</rewrite>

на вашем сайте mydomain.com - вы можете сделать один и тот же запрос источника, и нет необходимости в каких-либо запросах опций:)

Ответ 14

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

if (req.http.host == "CUSTOM_URL" ) {
set resp.http.Access-Control-Allow-Origin = "*";
if (req.method == "OPTIONS") {
   set resp.http.Access-Control-Max-Age = "1728000";
   set resp.http.Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, PATCH, OPTIONS";
   set resp.http.Access-Control-Allow-Headers = "Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since";
   set resp.http.Content-Length = "0";
   set resp.http.Content-Type = "text/plain charset=UTF-8";
   set resp.status = 204;
}

}

Ответ 15

Возможно, есть решение (но я его не тестировал): вы можете использовать CSP (Политика безопасности контента), чтобы включить удаленный домен и браузеры, возможно, пропустит проверку запроса CORS OPTIONS.

Я, если найду какое-то время, буду проверять это и обновлять этот пост!

CSP: https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Content-Security-Policy

Спецификация CSP: https://www.w3.org/TR/CSP/