Я строю веб-API. Я обнаружил, что всякий раз, когда я использую Chrome для POST, GET для моего API, всегда есть запрос OPTIONS, отправляемый перед реальным запросом, что довольно раздражает. В настоящее время я получаю сервер игнорировать любые запросы 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
редактировать 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, если он сочтет это необходимым.
Есть два способа обойти это:
- Убедитесь, что ваш запрос является "простым запросом"
- Установите
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/