google chrome - quantum - Chrome v37/38 CORS falla(nuevamente) con 401 para las solicitudes previas al vuelo de OPCIONES
tamper chrome (4)
@Cornel Masson, ¿resolviste el problema? No entiendo por qué su servidor le está pidiendo que autentique la solicitud de OPCIONES, pero estoy enfrentando este mismo problema con un servidor de SAP NetWeaver. He leído toda la especificación de CORS (lo recomiendo) para poder aclarar algunas de sus dudas.
Sobre tu sentencia
En la aplicación Angular he establecido explícitamente los siguientes encabezados de solicitud. AFAIK esta configuración para withCredentials debe garantizar que las credenciales se envíen incluso para las solicitudes de OPCIONES:
- De acuerdo con la especificación CORS cuando un agente de usuario (por lo tanto, un navegador) realiza una verificación previa de una solicitud (solicitudes con el método HTTP OPTIONS), DEBE excluir las credenciales del usuario (cookies, autenticación HTTP ...) por lo que no se puede solicitar como autenticada ninguna solicitud OPTIONS. . El navegador solicitará como autenticada la solicitud real (la que tiene el método HTTP solicitado como GET, POST ...), pero no la solicitud de verificación previa.
- Por lo tanto, los navegadores NO DEBEN enviar las credenciales en la solicitud de OPCIONES. Lo harán en pedidos reales. Si escribe withCredentials = true, el navegador debería hacer lo que le digo.
Según su frase:
Parece que Chrome está preparando todos mis POST debido al tipo de contenido: "application / json":
- La especificación también dice que el navegador realizará una solicitud de verificación previa cuando el encabezado no sea un "encabezado simple" y aquí tiene lo que significa:
Se dice que un encabezado es un encabezado simple si el nombre del campo del encabezado es una coincidencia ASCII que no distingue entre mayúsculas y minúsculas para Aceptar, Aceptar-Idioma o Lenguaje de contenido o si es una coincidencia ASCII que no distingue entre mayúsculas y minúsculas para el Contenido-Tipo y el campo de encabezado el tipo de medio de valor (excluyendo los parámetros) es una coincidencia ASCII que no distingue entre mayúsculas y minúsculas para application / x-www-form-urlencoded , multipart / form-data o text / plain .
- application / json no está incluido, por lo que el navegador DEBE realizar una verificación previa de la solicitud.
EDIT: Acabo de encontrar a una persona con el mismo problema que refleja los problemas reales, y si usa el mismo servidor que él, tendrá suerte, https://evolpin.wordpress.com/2012/10/12/the-cors/
A partir de la versión 37 de Chrome, las solicitudes previas al vuelo y entre dominios fallan (de nuevo) si el servidor tiene la autenticación habilitada, aunque todas las cabeceras CORS están configuradas correctamente. Esto está en localhost
(mi dev PC).
Algunos de ustedes pueden estar al tanto de la historia de los errores de Chrome / CORS / auth, especialmente cuando estaba involucrado HTTPS. Mi problema no implica HTTPS: tengo una aplicación AngularJS servida desde localhost:8383
hablando con un servidor Java (Jetty) en localhost:8081
que tiene la autenticación HTTP BASIC activada. Los GET funcionan bien, pero los POST fallan con un 401:
XMLHttpRequest cannot load http://localhost:8081/cellnostics/rest/patient.
Invalid HTTP status code 401
Anteriormente he escrito un filtro CORS personalizado (Java) que establece los encabezados CORS correctos, que funcionaron hasta v36. Falla en v37 y también la última v38 (38.0.2125.101 m). Todavía funciona como se esperaba con Internet Explorer 11 (11.0.9600) y Opera 12.17 (compilación 1863).
Las solicitudes GET tienen éxito, pero las POST fallan. Parece que Chrome está preparando todos mis POST debido al tipo de contenido: "application / json", y que es la solicitud de OPCIONES pre-desplegada la que está fallando.
En la aplicación Angular he establecido explícitamente los siguientes encabezados de solicitud. AFAIK esta configuración para withCredentials
debe garantizar que las credenciales se envíen incluso para las solicitudes de OPCIONES:
//Enable cross domain calls
$httpProvider.defaults.useXDomain = true;
//Send all requests, even OPTIONS, with credentials
$httpProvider.defaults.withCredentials = true;
A continuación se muestra la solicitud / respuesta. Puede ver que el método OPCIONES está habilitado en el encabezado Access-Control-Allow-Methods
. También puede ver que el origen de la aplicación Javascript está habilitado explícitamente: 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"
¿Alguien tiene alguna idea de qué otra cosa debería hacer? Me aseguré de borrar el caché de Chrome antes de probar, reiniciar y asegurarse de que no quedaban procesos de Chrome en ejecución antes del reinicio, así que estoy bastante seguro de que no hubo problemas de caché de autenticación persistentes.
He tenido que cambiar a IE 11 para probar mi desarrollo web. El hecho de que la misma configuración de cliente y servidor todavía funcione para IE y Opera, y el hecho de que haya un historial de errores de Chrome / CORS, me hace sospechar de Chrome.
EDIT: Aquí hay un extracto de la lista de eventos de Chrome net-internals:
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
Así que parece que el encabezado de Autorización no se envía con las OPCIONES previas al vuelo, a pesar de que establecí explícitamente con withCredentials = true
.
Sin embargo, ¿por qué IE y Opera todavía funcionan? ¿Es Chrome más compatible con los estándares en este sentido? ¿Por qué funcionó y luego comenzó a fallar desde v37?
EDITAR: Las herramientas de desarrollo de Chrome no muestran el Content-Type
de Content-Type
de la solicitud en los volcados anteriores, pero aquí está en el registro de la red. La primera foto muestra la POST cuando la autenticación del servidor está deshabilitada, con el tipo de contenido enviado correctamente como ''aplicación / json''. La segunda foto es cuando la autenticación está habilitada, mostrando que la solicitud de OPCIONES falla (parece que las OPCIONES siempre se envían con el tipo de contenido ''texto / sin formato'').
En MS IIS, implementé otra solución alternativa al anular el ciclo de vida de la página estándar de Microsoft, es decir, el procesamiento de OPCIONES al comienzo de la solicitud HTTP en 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();
}
}
}
Estábamos experimentando este mismo problema al intentar depurar una aplicación de aplicaciones para el usuario de Angular 4 que se ejecuta en localhost: 4200 (usando el Angular CLI Live Development Server). La aplicación Angular realiza solicitudes http a una aplicación ASP .Net WebApi2 que se ejecuta en localhost (servidor web IIS) con autenticación de Windows. El problema solo se produjo al realizar una solicitud POST en Chrome (aunque nuestra WebApi está configurada para CORs). Pudimos solucionar temporalmente el problema iniciando Fiddler y ejecutando un proxy inverso hasta que encontramos esta publicación (Gracias).
El mensaje de error en el depurador de Chrome: la respuesta a la solicitud de verificación previa no pasa la verificación de control de acceso: no hay encabezado ''Access-Control-Allow-Origin'' presente en el recurso solicitado
Agregar el siguiente código a nuestro archivo Web Api2 - Global.asax resolvió este problema.
Si está buscando el "CorsHandler", simplemente puede reemplazar la publicación de George con los valores de cadena codificados, de la siguiente manera:
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();
}
}
Saludos cordiales,
Chris
Igual que aquí. Yo uso la autenticación NTLM de Windows. Hasta Chrome versión 37 funcionó bien. En las versiones 37, 38, falla con 401 (no autorizado) debido a que falta el encabezado de autorización en las OPCIONES previas al vuelo tanto en PUT como en POST.
El lado del servidor es Microsoft Web Api 2.1. Probé varios CORS, incluido el último paquete NuGet de Microsoft, sin éxito.
Tengo que solucionar el problema de Chrome enviando una solicitud GET en lugar de POST, y dividiendo datos bastante grandes en varias solicitudes, ya que la URL tiene un límite de tamaño natural.
Aquí están los encabezados de solicitud / respuesta:
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