Chrome v37 / 38 CORS не работает (снова) с 401 для запросов перед полетом

Начиная с версии Chrome 37, запросы на междоменные запросы не выполняются (снова), если сервер имеет аутентификацию, даже если все заголовки CORS установлены правильно. Это на localhost (мой dev ПК).

Некоторым из вас может быть известно об истории ошибок Chrome / CORS / auth, особенно при использовании HTTPS. Моя проблема не связана с HTTPS: у меня есть приложение AngularJS, обслуживаемое с localhost:8383 разговаривающее с сервером Java (Jetty) на localhost:8081 , активированное HTTP BASIC. GET работает нормально, но POST не работают с 401:

 XMLHttpRequest cannot load http://localhost:8081/cellnostics/rest/patient. Invalid HTTP status code 401 

Я ранее написал пользовательский (Java) фильтр CORS, который устанавливает правильные заголовки CORS, которые работали до v36. Он терпит неудачу в v37, а также последний v38 (38.0.2125.101 м). Он по- прежнему работает в Internet Explorer 11 (11.0.9600) и Opera 12.17 (assembly 1863).

Запросы GET успешны, но POST не работают. Похоже, что Chrome предварительно отправляет все мои POST-сообщения из-за типа контента: «application / json» и что это запрошенный запрос OPTIONS, который не срабатывает.

В приложении «Угловое» я явно устанавливаю следующие заголовки запросов. AFAIK этот параметр для withCredentials должен гарантировать, что учетные данные отправляются даже для запросов OPTIONS:

 //Enable cross domain calls $httpProvider.defaults.useXDomain = true; //Send all requests, even OPTIONS, with credentials $httpProvider.defaults.withCredentials = true; 

Ниже приведен запрос / ответ. Вы можете видеть, что метод OPTIONS включен в заголовке Access-Control-Allow-Methods . Вы также можете увидеть, что источник приложения Javascript явно включен: Access-Control-Allow-Origin: http://localhost:8383 .

 Remote Address:[::1]:8081 Request URL:http://localhost:8081/cellnostics/rest/medicaltest Request Method:OPTIONS Status Code:401 Full authentication is required to access this resource Request headers: Accept:*/* Accept-Encoding:gzip,deflate,sdch Accept-Language:en-US,en;q=0.8,af;q=0.6 Access-Control-Request-Headers:accept, content-type Access-Control-Request-Method:POST Connection:keep-alive Host:localhost:8081 Origin:http://localhost:8383 Referer:http://localhost:8383/celln-web/index.html User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36 Response headers: Access-Control-Allow-Credentials:true Access-Control-Allow-Headers:Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept Access-Control-Allow-Methods:POST, GET, OPTIONS, PUT, DELETE Access-Control-Allow-Origin:http://localhost:8383 Access-Control-Max-Age:3600 Content-Length:0 Server:Jetty(8.1.8.v20121106) WWW-Authenticate:Basic realm="Cellnostics" 

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

Мне пришлось переключиться на IE 11 для тестирования моей веб-разработки. Тот факт, что одна и та же настройка клиента и сервера по-прежнему работает для IE и Opera, а также тот факт, что есть история ошибок Chrome / CORS, заставляет меня подозревать Chrome.

EDIT: Вот выдержка из списка событий net-internals в Chrome:

 t=108514 [st=0] +URL_REQUEST_START_JOB [dt=4] --> load_flags = 336011264 (BYPASS_DATA_REDUCTION_PROXY | DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES | MAYBE_USER_GESTURE | VERIFY_EV_CERT) --> method = "OPTIONS" --> priority = "LOW" --> url = "http://localhost:8081/cellnostics/rest/patient" ... t=108516 [st=2] HTTP_TRANSACTION_SEND_REQUEST_HEADERS --> OPTIONS /cellnostics/rest/patient HTTP/1.1 Host: localhost:8081 Connection: keep-alive Access-Control-Request-Method: POST Origin: http://localhost:8383 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36 Access-Control-Request-Headers: accept, content-type Accept: */* Referer: http://localhost:8383/celln-web/index.html Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8,af;q=0.6 

Таким образом, похоже, что заголовок авторизации не отправляется с предварительным withCredentials = true OPTIONS, хотя я явно задал withCredentials = true .

Однако почему IE и Opera все еще работают? Является ли Chrome более стандартизированным в этом отношении? Почему это сработало, а затем началось с отказа от версии v37?

EDIT: инструменты Chrome dev не показывают Content-Type запроса в дампах выше, но здесь он из журнала Network. Первая фотография показывает POST, когда аутентификация сервера отключена, а тип контента правильно отправлен как «application / json». Второй рис., Когда включен auth, показывая, что запрос OPTIONS не работает (кажется, OPTIONS всегда отправляется с типом контента «text / plain»?).

CORS POST с NO auth на сервереCORS POST с включенным auth на сервере

@Cornel Masson, вы решили проблему? Я не понимаю, почему ваш сервер просит вас аутентифицировать запрос OPTIONS, но я столкнулся с этой же проблемой с сервером SAP NetWeaver. Я прочитал всю спецификацию CORS (я рекомендую), поэтому я могу разъяснить вам некоторые из ваших сомнений.

О вашем предложении

В приложении «Угловое» я явно устанавливаю следующие заголовки запросов. AFAIK этот параметр для withCredentials должен гарантировать, что учетные данные отправляются даже для запросов OPTIONS:

  • В соответствии со спецификацией CORS, когда пользовательский агент (таким образом, браузер) предваряет запрос (запросы с помощью метода OPTIONS HTTP), он ДОЛЖЕН исключать учетные данные пользователя (cookies, HTTP-аутентификация …), поэтому любой запрос OPTIONS не может запрашиваться как аутентифицированный , Браузер запросит как аутентифицированный фактический запрос (тот, у кого запрошенный метод HTTP, такой как GET, POST …), но не запрос предполетной проверки.
  • Поэтому браузеры НЕ ДОЛЖНЫ отправлять учетные данные в запрос OPTIONS. Они будут делать в реальных запросах. Если вы пишете withCredentials = true, браузер должен делать то, что я говорю.

Согласно вашему предложению:

Похоже, что Chrome все же отправляет все мои POST-сообщения из-за типа контента: «application / json»:

  • В спецификации также говорится, что браузер запрашивает запрос перед полетом, когда заголовок не является «простым заголовком», и здесь у вас есть то, что это означает:

Заголовок называется простым заголовком, если имя поля заголовка является несоответствующим регистру ASCII совпадению для Accept, Accept-Language или Content-Language или если это несовместимое с ASCII совпадение для Content-Type и поле заголовка (исключая параметры) – это ASCII-регистр без учета регистра для приложения / x-www-form-urlencoded , multipart / form-data или text / plain .

  • Приложение / json не включено, поэтому браузер ДОЛЖЕН предварять запрос, как он.
  • Если кто-нибудь найдет решение, это будет оценено.

    EDIT: Я просто нашел человека с той же проблемой, которая отражает реальные проблемы, и если вы используете тот же сервер, что и он, вам повезет, https://evolpin.wordpress.com/2012/10/12/the-cors/

    Тоже самое. Я использую аутентификацию Windows NTLM. До версии Chrome 37 работало нормально. В версиях 37, 38 он не работает с 401 (Несанкционированный) из-за отсутствия заголовка авторизации в предполетных ВАРИАНТАХ на обоих PUT и POST.

    На стороне сервера находится Microsoft Web Api 2.1. Я пробовал различные CORS, включая последний пакет NuGet от Microsoft, но безрезультатно.

    Мне нужно обходить Chrome, отправив GET-запрос вместо POST и разбив довольно огромные данные по нескольким запросам, так как URL имеет ограничение по размеру, естественно.

    Вот заголовки запроса / ответа:


     Request URL: http://localhost:8082/api/ConfigurationManagerFeed/ Method: OPTIONS Status: 401 Unauthorized Request Headers Accept: */* Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8,ru;q=0.6 Access-Control-Request-Headers: accept, content-type Access-Control-Request-Method: POST Connection: keep-alive Host: localhost:8082 Origin: http://localhost:8383 Referer: http://localhost:8383/Application/index.html User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36 X-DevTools-Emulate-Network-Conditions-Client-Id: 49E7FC68-A65C-4318-9292-852946051F27 Response Headers Cache-Control: private Content-Length: 6388 Content-Type: text/html; charset=utf-8 Date: Fri, 24 Oct 2014 13:40:07 GMT Server: Microsoft-IIS/7.5 WWW-Authenticate: Negotiate NTLM X-Powered-By: ASP.NET 

    В MS IIS я реализовал еще один способ обхода путем переопределения жизненного цикла стандартной страницы Microsoft, то есть обработки ВАРИАНТОВ прямо в начале HTTP-запроса в global.ascx:

     public class Global : HttpApplication { /// Check and cofigure CORS Pre-flight request on Begin Request lifecycle ///  protected void Application_BeginRequest() { if (Request.Headers.AllKeys.Contains(CorsHandler.Origin) && Request.HttpMethod == "OPTIONS") { Response.StatusCode = (int)HttpStatusCode.OK; Response.Headers.Add(CorsHandler.AccessControlAllowCredentials, "true"); Response.Headers.Add(CorsHandler.AccessControlAllowOrigin, Request.Headers.GetValues(CorsHandler.Origin).First()); string accessControlRequestMethod = Request.Headers.GetValues(CorsHandler.AccessControlRequestMethod).FirstOrDefault(); if (accessControlRequestMethod != null) { Response.Headers.Add(CorsHandler.AccessControlAllowMethods, accessControlRequestMethod); } var hdrs = Request.Headers.GetValues(CorsHandler.AccessControlRequestHeaders).ToList(); hdrs.Add("X-Auth-Token"); string requestedHeaders = string.Join(", ", hdrs.ToArray()); Response.Headers.Add(CorsHandler.AccessControlAllowHeaders, requestedHeaders); Response.Headers.Add("Access-Control-Expose-Headers", "X-Auth-Token"); Response.Flush(); } } } , public class Global : HttpApplication { /// Check and cofigure CORS Pre-flight request on Begin Request lifecycle ///  protected void Application_BeginRequest() { if (Request.Headers.AllKeys.Contains(CorsHandler.Origin) && Request.HttpMethod == "OPTIONS") { Response.StatusCode = (int)HttpStatusCode.OK; Response.Headers.Add(CorsHandler.AccessControlAllowCredentials, "true"); Response.Headers.Add(CorsHandler.AccessControlAllowOrigin, Request.Headers.GetValues(CorsHandler.Origin).First()); string accessControlRequestMethod = Request.Headers.GetValues(CorsHandler.AccessControlRequestMethod).FirstOrDefault(); if (accessControlRequestMethod != null) { Response.Headers.Add(CorsHandler.AccessControlAllowMethods, accessControlRequestMethod); } var hdrs = Request.Headers.GetValues(CorsHandler.AccessControlRequestHeaders).ToList(); hdrs.Add("X-Auth-Token"); string requestedHeaders = string.Join(", ", hdrs.ToArray()); Response.Headers.Add(CorsHandler.AccessControlAllowHeaders, requestedHeaders); Response.Headers.Add("Access-Control-Expose-Headers", "X-Auth-Token"); Response.Flush(); } } } 

    Мы столкнулись с этой же проблемой при попытке отладки внешнего приложения Angular 4, работающего на localhost: 4200 (с использованием Angular CLI Live Development Server). Угловое приложение делает HTTP-запросы к приложению ASP .Net WebApi2, запущенному на локальном хосте (веб-сервере IIS) с проверкой подлинности Windows. Ошибка возникла только при выполнении запроса POST в Chrome (хотя наш WebApi настроен для COR). Мы смогли временно решить проблему, запустив Fiddler и запустив обратный прокси до тех пор, пока мы не найдем этот пост (спасибо).

    Сообщение об ошибке в отладчике Chrome: ответ на запрос предварительной проверки не проходит проверку контроля доступа: заголовок «Access-Control-Allow-Origin» отсутствует на запрошенном ресурсе

    Добавление приведенного ниже кода в наш веб-файл Api2 – Global.asax разрешило эту проблему.

    Если вы ищете «CorsHandler», вы можете просто заменить запись Джорджа строковыми строковыми значениями следующим образом:

      protected void Application_BeginRequest() { if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS") { Response.StatusCode = (int)HttpStatusCode.OK; Response.Headers.Add("Access-Control-Allow-Credentials", "true"); Response.Headers.Add("Access-Control-Allow-Origin", Request.Headers.GetValues("Origin").First()); string accessControlRequestMethod = Request.Headers.GetValues("Access-Control-Request-Method").FirstOrDefault(); if (accessControlRequestMethod != null) { Response.Headers.Add("Access-Control-Allow-Methods", accessControlRequestMethod); } var hdrs = Request.Headers.GetValues("Access-Control-Request-Headers").ToList(); hdrs.Add("X-Auth-Token"); string requestedHeaders = string.Join(", ", hdrs.ToArray()); Response.Headers.Add("Access-Control-Allow-Headers", requestedHeaders); Response.Headers.Add("Access-Control-Expose-Headers", "X-Auth-Token"); Response.Flush(); } } ,  protected void Application_BeginRequest() { if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS") { Response.StatusCode = (int)HttpStatusCode.OK; Response.Headers.Add("Access-Control-Allow-Credentials", "true"); Response.Headers.Add("Access-Control-Allow-Origin", Request.Headers.GetValues("Origin").First()); string accessControlRequestMethod = Request.Headers.GetValues("Access-Control-Request-Method").FirstOrDefault(); if (accessControlRequestMethod != null) { Response.Headers.Add("Access-Control-Allow-Methods", accessControlRequestMethod); } var hdrs = Request.Headers.GetValues("Access-Control-Request-Headers").ToList(); hdrs.Add("X-Auth-Token"); string requestedHeaders = string.Join(", ", hdrs.ToArray()); Response.Headers.Add("Access-Control-Allow-Headers", requestedHeaders); Response.Headers.Add("Access-Control-Expose-Headers", "X-Auth-Token"); Response.Flush(); } } 

    С уважением,

    Крис

  • Как сказать chrome открыть инструменты для разработчиков для определенных доменов сайта?
  • Как заблокировать доступ к определенным веб-сайтам через браузер?
  • Есть ли способ сделать Ctrl + f в Chrome, используя выделенный текст, в соответствии с Firefox?
  • Браузер показывает странные китайские абзацы
  • Что делает объект jQuery отображаться как массив в инструментах разработчика Chrome?
  • Блокировка веб-сайта после двух посещений в тот же день в Google Chrome
  • Как я могу запретить сайты из omnibar Chrome?
  • В Chrome отключено подключение IPv6, таймауты в Firefox
  • Как поддерживать порядок ссылок типа поиска Google , А не переупорядочивать?
  • Как вручную запускать HTTP-запросы POST с помощью Firefox или Chrome?
  • Есть ли способ закладки всех вкладок в Chrome?
  • Interesting Posts

    Имена файлов слишком длинные, и Windows не может открыть файлы

    Java: notify () vs. notifyAll () снова и снова

    Как узнать, что приложение установлено из игры Google или боковой загрузки?

    Ошибка при нажатии данных в Heroku: смещение часовых поясов за пределами диапазона

    Сделать Java runtime игнорировать serialVersionUID?

    ASP.NET эквивалент серверной части включает

    Static vs функции / переменные classа в classах Swift?

    Сортировка многомерного массива в VBA

    Почему Access 2013 не откроет файл .mdb?

    VueJs templating. Как загрузить внешние шаблоны

    Три монитора с Nvidia GeForce GT 525m и графикой Intel HD на Del XPS 15Z

    Какие функции имеют прогрессивные веб-приложения в сравнении с родными приложениями и наоборот, на Android

    Могу ли я навсегда запретить обновлениям безопасности Java от установки панели инструментов Yahoo?

    Почему я не могу определить статический метод в интерфейсе Java?

    java.util.zip.ZipException: ошибка при открытии zip-файла

    Давайте будем гением компьютера.