javascript - enable - AngularJS: OPCIONES llamada de verificación previa que precede a una solicitud $ http.post
enable cors (3)
Esto parece estar relacionado con el hecho de que está llegando a un punto final https
en su host local. Eso significa que probablemente estés usando algún tipo de certificado SSL autofirmado, lo que puede significar que Chrome considera que no es de confianza.
Primero intentaría ir directamente al punto final / authenticate y ver si Chrome te da una advertencia sobre un certificado no confiable. Ver si funciona aceptar la advertencia.
De lo contrario, posiblemente, mientras realiza las pruebas a nivel local, ¿puede golpear solo un punto final http
y ver si eso resuelve las cosas?
Estoy usando AngularJS v1.2.4.
Tuve un problema con Angular al enviar una llamada OPCIONES de verificación previa (Chrome mostraba la llamada OPCIONES como ''cancelada'') y la resolví con:
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common[''X-Requested-With''];
Eso funcionó para todas mis llamadas de recursos, y todo fue bueno.
Ahora estoy tratando de implementar la autenticación y una página de inicio de sesión que envía una solicitud POST a mi servidor con las credenciales del usuario. Estoy viendo el problema al que me enfrentaba antes, pero las llamadas de recursos de $ siguen funcionando bien.
Lo que es realmente frustrante es que el problema ocurre de manera intermitente; Cambiaré algunas opciones alrededor de los encabezados, luego funcionará un poco y dejaré de funcionar nuevamente sin ningún cambio de código.
Mi servidor está configurado para CORS y funciona bien con curl y otros clientes REST. Aquí hay un ejemplo:
curl -X OPTIONS -ik ''https://localhost:3001/authenticate'' -H "Origin: https://localhost:8001"
HTTP/1.1 200 OK
content-type: application/json; charset=utf-8
content-length: 2
cache-control: no-cache
access-control-allow-origin: *
access-control-max-age: 86400
access-control-allow-methods: GET, HEAD, POST, PUT, DELETE, OPTIONS
access-control-allow-headers: Authorization, Content-Type, If-None-Match, Access-Control-Allow-Headers, Content-Type
access-control-expose-headers: WWW-Authenticate, Server-Authorization
set-cookie: session=Fe26.2**94705d49717d1273197ae86ce6661775627d7c6066547b757118c90c056e393b*2KYqhATojPoQhpB2OwhDwg*W9GsJjK-F-UPqIIHTBHHZx1RXipo0zvr97_LtTLMscRkKqLqr8H6WiGd2kczVwL5M25FBlB1su0JZllq2QB-9w**5510263d744a9d5dc879a89b314f6379d17a39610d70017d60acef01fa63ec10*pkC9zEOJTY_skGhb4corYRGkUNGJUr8m5O1US2YhaRE; Secure; Path=/
Date: Wed, 18 Dec 2013 23:35:56 GMT
Connection: keep-alive
Aquí está la llamada $ http.post:
var authRequest = $http.post(''https://'' + $location.host() + '':3001/authenticate'', {email: email, password: password});
Cuando la llamada de mi aplicación funciona, así es como se ve la solicitud de OPCIONES:
Cuando no funciona, esta es la solicitud de OPCIONES:
Parece que faltan un montón de atributos de encabezado. ¿Alguien ha encontrado un problema similar?
Editar:
Solo para aclarar, cuando no funciona, la solicitud nunca llega al servidor; se cancela instantáneamente en el navegador.
En Firebug, los encabezados de solicitud son:
OPTIONS /authenticate HTTP/1.1
Host: localhost:3001
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:25.0) Gecko/20100101 Firefox/25.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.91,en-GB;q=0.82,fr-FR;q=0.73,fr;q=0.64,utf-8;q=0.55,utf;q=0.45,de-DE;q=0.36,de;q=0.27,en-sg;q=0.18,en-ca;q=0.09
Accept-Encoding: gzip, deflate
Origin: https://localhost:8001
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Proxy-Authorization: Basic cGF0cmljZUB6b25nLmNvbTpjaGFuZ2VtZQ==
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Actualizar:
Creo que he eliminado la posibilidad de un problema con el servidor, cambiando el host a un servidor inexistente. Sigo viendo el mismo comportamiento.
Aquí hay un código:
App.services.factory(''AuthService'', function ($http, $location, $q) {
var currentUser;
return {
authenticate: function (email, password) {
//promise to return
var deferred = $q.defer();
var authRequest = $http.post(''https://this.does.not.exist.com:3001/authenticate'', {email: email, password: password});
authRequest.success(function (data, status, header, config) {
currentUser = data;
console.log(''currentUser in service set to:'');
console.log(currentUser);
//resolve promise
deferred.resolve();
});
authRequest.error(function (data, status, header, config) {
console.log(''authentication error'');
console.log(status);
console.log(data);
console.log(header);
console.log(config);
//reject promise
deferred.reject(''authentication failed..'');
});
return deferred.promise;
},
isAuthenticated: function () {
return currentUser !== undefined;
}
};
});
y configuración HTTP:
App.config([''$httpProvider'', function ($httpProvider) {
$httpProvider.defaults.useXDomain = true;
//$httpProvider.defaults.headers.common = {};
console.log(''logging out headers'');
console.log($httpProvider.defaults);
console.log($httpProvider.defaults.headers.common);
console.log($httpProvider.defaults.headers.post);
console.log($httpProvider.defaults.headers.put);
console.log($httpProvider.defaults.headers.patch);
console.log(''end logging out headers'');
$httpProvider.defaults.headers.common = {Accept: "application/json, text/plain, */*"};
$httpProvider.defaults.headers.post = {"Content-Type": "application/json;charset=utf-8"};
console.log(''after: logging out headers'');
console.log($httpProvider.defaults.headers.common);
console.log($httpProvider.defaults.headers.post);
console.log($httpProvider.defaults.headers.put);
console.log($httpProvider.defaults.headers.patch);
console.log(''after: end logging out headers'');
$httpProvider.interceptors.push(function ($location, $injector) {
return {
''request'': function (config) {
console.log(''in request interceptor!'');
var path = $location.path();
console.log(''request: '' + path);
//injected manually to get around circular dependency problem.
var AuthService = $injector.get(''AuthService'');
console.log(AuthService);
console.log(config);
if (!AuthService.isAuthenticated() && $location.path() != ''/login'') {
console.log(''user is not logged in.'');
$location.path(''/login'');
}
//add headers
console.log(config.headers);
return config;
}
};
});
}]);
Muchísimas gracias a Michael Cox por indicarme la dirección correcta . Acepto su respuesta ya que me llevó a la solución, pero aquí hay más detalles:
Buscando en el tema https, encontré:
- ¿Por qué Chrome cancelar la solicitud de opción de CORS?
- https://code.google.com/p/chromium/issues/detail?id=141839
Aunque mi problema era ligeramente diferente. Todavía no funcionaba después de seguir las instrucciones en los enlaces anteriores. Leí el mensaje "no confiable" de Chrome y fue algo así como "estás intentando acceder a mylocalhost.com pero el servidor se representa a sí mismo como".
Resulta que mi certificado autofirmado creado apresuradamente fue "server.crt" cuando debería ser "mylocalhost.crt"
No puede tener allow-credentials
junto con Access-Control-Allow-Origin: *
.
Nota importante: al responder a una solicitud con credenciales, el servidor debe especificar un dominio y no puede usar el comodín.
Con respecto a las solicitudes GET, no necesitan verificación previa, etc., si no tienen encabezados especiales.
Fuente: Mozilla Developer Network . (Mejor enlace CORS en la web!)