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 (сборка 1863).

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

В приложении «Угловое» я явно устанавливаю следующие заголовки запросов. AFAIK этот параметр //Enable cross domain calls $httpProvider.defaults.useXDomain = true; //Send all requests, even OPTIONS, with credentials $httpProvider.defaults.withCredentials = true; должен гарантировать, что учетные данные отправляются даже для запросов OPTIONS:

Access-Control-Allow-Methods

Ниже приведен запрос / ответ. Вы можете видеть, что метод OPTIONS включен в Access-Control-Allow-Origin: http://localhost:8383заголовке. Вы можете также видеть , что происхождение этого приложения в JavaScript явно включено: 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" .

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

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

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

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

withCredentials = true

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

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

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

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

google-chrome,cors,

25

Ответов: 4


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

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

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

  • В соответствии со спецификацией CORS, когда пользовательский агент (таким образом, браузер) предваряет запрос (запросы с помощью метода OPTIONS HTTP), он ДОЛЖЕН исключать учетные данные пользователя (файлы cookie, 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

1

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

public class Global : HttpApplication
{
    /// <summary>Check and cofigure CORS Pre-flight request on Begin Request lifecycle
    /// </summary>
    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();
        }
    }
}

1

Мы столкнулись с этой же проблемой при попытке отладки внешнего приложения 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();
        }
    }

С уважением,

Крис

Google-хром, CORS,
Похожие вопросы
Яндекс.Метрика