web-dev-qa-db-fra.com

AngularJS: OPTION de contrôle en amont précédant une demande $ http.post

J'utilise AngularJS v1.2.4.

J'ai rencontré un problème avec Angular envoi d'un appel OPTIONS de contrôle en amont (Chrome affichait l'appel OPTIONS comme "annulé") et l'ai résolu avec:

$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];

Cela a fonctionné pour tous mes appels de ressources $, et tout s'est bien passé.

Maintenant, j'essaie d'implémenter l'authentification et une page de connexion qui envoie une demande POST à mon serveur avec les informations d'identification de l'utilisateur. Je vois le problème auquel j'étais confronté auparavant, mais $ resource appelle fonctionnent toujours bien.

Ce qui est vraiment frustrant, c'est que le problème se produit par intermittence; Je vais modifier quelques options entourant les en-têtes, puis cela fonctionnera un peu et cesser de fonctionner à nouveau sans aucun changement de code.

Mon serveur est configuré pour CORS et fonctionne correctement avec curl et d'autres clients REST. Voici un exemple:

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

Voici l'appel $ http.post:

var authRequest = $http.post('https://' + $location.Host() + ':3001/authenticate', {email: email, password: password});

Lorsque l'appel de mon application fonctionne, voici à quoi ressemble la demande OPTIONS:

enter image description here

Quand cela ne fonctionne pas, voici la requête OPTIONS:

enter image description here

Il semble que de nombreux attributs d'en-tête soient manquants. Quelqu'un a-t-il rencontré un problème similaire?

Modifier:

Juste pour clarifier, quand cela ne fonctionne pas, la demande ne parvient jamais au serveur - elle est instantanément abandonnée dans le navigateur.

enter image description here

Dans Firebug, les en-têtes de demande sont:

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

enter image description here

Mise à jour:

J'ai éliminé l'éventuel problème avec le serveur, je pense, en changeant l'hôte en un serveur inexistant. Toujours voir le même comportement.

Voici du code:

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;
        }
    };
});

et HTTP Config:

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;
            }
        };
    });
}]);
29
shaunlim

Cela semble être lié au fait que vous atteignez un point de terminaison https sur votre hôte local. Cela signifie que vous utilisez probablement une sorte de certificat SSL auto-signé, ce qui peut signifier Chrome le considère comme non fiable.

J'essaierais d'abord d'aller directement au point de terminaison/authenticate et de voir si Chrome vous donne un avertissement concernant un certificat non approuvé. Voir si l'acceptation de cet avertissement fonctionne.

Sinon, peut-être pendant que vous testez localement, vous pouvez frapper juste un point de terminaison http et voir si cela résout les choses?

13
Michael Cox

Un grand merci à Michael Cox pour m'avoir pointé dans la bonne direction . J'accepte sa réponse car elle m'a conduit à la solution, mais voici plus de détails:

En examinant le problème https, j'ai trouvé:

Mon problème était cependant légèrement différent. Cela ne fonctionnait toujours pas après avoir suivi les instructions dans les liens ci-dessus. J'ai lu attentivement le message chrome "non fiable" et c'était quelque chose comme "vous essayez d'accéder à mylocalhost.com mais le serveur se présente comme").

Il s'avère que mon certificat auto-signé créé à la hâte était "server.crt" alors qu'il devrait être "mylocalhost.crt"

9
shaunlim

Vous ne pouvez pas avoir allow-credentials ensemble avec Access-Control-Allow-Origin: *.

Remarque importante: lors de la réponse à une demande d'informations d'identification, le serveur doit spécifier un domaine et ne peut pas utiliser le joker.

Concernant les requêtes GET, ils n'ont pas besoin de contrôle en amont, etc. s'ils n'ont pas d'en-têtes spéciaux.

Source: Mozilla Developer Network . (Meilleur lien CORS sur le web!)

7
Zut