Ajout d'un en-tête personnalisé à la requête HTTP à l'aide d'angular.js

89

Je suis novice en angular.js, et j'essaye d'ajouter quelques en-têtes à une requête:

   var config = {headers: {
            'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
            'Accept': 'application/json;odata=verbose'
        }
    };

   $http.get('https://www.example.com/ApplicationData.svc/Malls(1)/Retailers', config).success(successCallback).error(errorCallback);

J'ai regardé toute la documentation, et cela me semble que cela devrait être correct.

Lorsque j'utilise un fichier local pour l'URL dans le $http.get, je vois la requête HTTP suivante sur l'onglet réseau dans Chrome:

GET /app/data/offers.json HTTP/1.1
Host: www.example.com
Connection: keep-alive
Cache-Control: max-age=0
If-None-Match: "0f0abc9026855b5938797878a03e6889"
Authorization: Basic Y2hhZHN0b25lbWFuOkNoYW5nZV9tZQ==
Accept: application/json;odata=verbose
X-Requested-With: XMLHttpRequest
If-Modified-Since: Sun, 24 Mar 2013 15:58:55 GMT
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
X-Testing: Testing
Referer: http://www.example.com/app/index.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

Comme vous pouvez le voir, les deux en-têtes ont été ajoutés correctement. Mais lorsque je change l'URL pour celle indiquée $http.getci - dessus (sauf en utilisant la vraie adresse, pas example.com), alors j'obtiens:

OPTIONS /ApplicationData.svc/Malls(1) HTTP/1.1
Host: www.datahost.net
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://mpon.site44.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
Access-Control-Request-Headers: accept, origin, x-requested-with, authorization, x-testing
Accept: */*
Referer: http://mpon.site44.com/app/index.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

La seule différence de code entre ces deux est que pour le premier, l'URL est un fichier local et pour le second, l'URL est un serveur distant. Si vous regardez le deuxième en-tête de demande, il n'y a pas d'en-tête d'authentification et Acceptsemble utiliser une valeur par défaut au lieu de celle spécifiée. En outre, la première ligne indique maintenant OPTIONSau lieu de GET(bien que ce Access-Control-Request-Methodsoit GET).

Une idée de ce qui ne va pas avec le code ci-dessus, ou comment obtenir les en-têtes supplémentaires inclus en utilisant lorsque vous n'utilisez pas un fichier local comme source de données?

trentclowater
la source
2
Cela ressemble à un problème CORS
Kevin Hakanson
C'était en effet un problème CORS. Le serveur n'a pas été configuré pour renvoyer l'en-tête Access-Control-Allow-Origin :. Si vous souhaitez rédiger une réponse avec votre commentaire et un peu de détails sur CORS, j'accepterai votre réponse. La réponse ci-dessous de Dmitry Evseev et éditée par vous était proche, mais pas vraiment le problème réel.
trentclowater
1
Chrome effectue le contrôle en amont de la demande de recherche d'en-têtes CORS si la demande concerne plusieurs domaines. Vérifiez ma réponse.
Asim KT

Réponses:

66

J'ai pris ce que tu avais et j'ai ajouté un autre en- X-Testingtête

var config = {headers:  {
        'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
        'Accept': 'application/json;odata=verbose',
        "X-Testing" : "testing"
    }
};

$http.get("/test", config);

Et dans l'onglet Réseau Chrome, je les vois être envoyés.

GET /test HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Accept: application/json;odata=verbose
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
Authorization: Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==
X-Testing: testing
Referer: http://localhost:3000/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

Ne les voyez-vous pas depuis le navigateur ou sur le serveur? Essayez les outils du navigateur ou un proxy de débogage et voyez ce qui est envoyé.

Kevin Hakanson
la source
Je n'ai pas accès au serveur et sur le navigateur, j'utilise Firefox, mais je vois les en-têtes que j'ai ajoutés à la question d'origine ci-dessus. Je ne vois pas où vous pouvez afficher les en-têtes sur l'onglet des ressources dans Chrome.
trentclowater
Désolée, j'ai ajouté une modification à votre réponse qui devait figurer dans ma question d'origine.
trentclowater
Je voulais dire l'onglet réseau des outils de développement, pas les ressources - réponse des mises à jour
Kevin Hakanson
J'ai ajouté plus d'informations à la question. Il semble que les en-têtes sont ajoutés dans un cas, mais pas dans un autre.
trentclowater
21

Authentification de base à l'aide de la méthode HTTP POST:

$http({
    method: 'POST',
    url: '/API/authenticate',
    data: 'username=' + username + '&password=' + password + '&email=' + email,
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "X-Login-Ajax-call": 'true'
    }
}).then(function(response) {
    if (response.data == 'ok') {
        // success
    } else {
        // failed
    }
});

... et appel de méthode GET avec en-tête:

$http({
    method: 'GET',
    url: '/books',
    headers: {
        'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
        'Accept': 'application/json',
        "X-Login-Ajax-call": 'true'
    }
}).then(function(response) {
    if (response.data == 'ok') {
        // success
    } else {
        // failed
    }
});
Ajay Kumar
la source
La meilleure réponse.
Yoda
9

Si vous souhaitez ajouter vos en-têtes personnalisés à TOUTES les demandes, vous pouvez modifier les valeurs par défaut sur $ httpProvider pour toujours ajouter cet en-tête…

app.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.defaults.headers.common = { 
        'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
        'Accept': 'application/json;odata=verbose'
      };
}]);
Korayem
la source
ALL mais OPTIONS demande c'est-à-dire
Rocco
bel exemple. cela peut-il être utilisé pour mettre en cache le jeton pour rediriger les pages?
Martian2049
7

ma suggestion sera d'ajouter un paramètre d'appel de fonction comme celui-ci à l'intérieur de la fonction, vérifiez l'en-tête qui lui convient. Je suis sûr que cela fonctionnera certainement. cela fonctionne parfaitement pour moi.

function getSettings(requestData) {
    return {
        url: requestData.url,
        dataType: requestData.dataType || "json",
        data: requestData.data || {},
        headers: requestData.headers || {
            "accept": "application/json; charset=utf-8",
            'Authorization': 'Bearer ' + requestData.token
        },
        async: requestData.async || "false",
        cache: requestData.cache || "false",
        success: requestData.success || {},
        error: requestData.error || {},
        complete: requestData.complete || {},
        fail: requestData.fail || {}
    };
}

puis appelez vos données comme ceci

    var requestData = {
        url: 'API end point',
        data: Your Request Data,
        token: Your Token
    };

    var settings = getSettings(requestData);
    settings.method = "POST"; //("Your request type")
    return $http(settings);
Riyad Ul Islam
la source
2

Ce que vous voyez pour la demande OPTIONS est correct. Les en-têtes d'autorisation n'y sont pas exposés.

Mais pour que l'authentification de base fonctionne, vous devez ajouter: withCredentials = true;à votre fichier var config.

À partir de la documentation AngularJS $ http :

withCredentials - {boolean}- s'il faut définir l' withCredentials indicateur sur l'objet XHR. Voir les demandes avec des informations d'identification pour plus d'informations.

Dmitry Evseev
la source
1

Et quelle est la réponse du serveur? Il devrait répondre un 204 et ensuite vraiment envoyer le GET que vous demandez.

Dans les OPTIONS, le client vérifie si le serveur autorise les requêtes CORS. Si cela vous donne quelque chose de différent d'un 204, vous devez configurer votre serveur pour envoyer les en-têtes Allow-Origin corrects.

La façon dont vous ajoutez des en-têtes est la bonne façon de le faire.

ghostbar
la source
1

Chrome effectue le contrôle en amont de la demande de recherche des en-têtes CORS. Si la demande est acceptable, elle enverra alors la vraie demande. Si vous faites ce cross-domain, vous devrez simplement vous en occuper ou bien trouver un moyen de rendre la requête non-cross-domain. C'est par conception.

Contrairement aux requêtes simples (discutées ci-dessus), les requêtes "pré-contrôlées" envoient d'abord une requête HTTP par la méthode OPTIONS à la ressource de l'autre domaine, afin de déterminer si la requête réelle peut être envoyée en toute sécurité. Les demandes intersites sont contrôlées en amont comme ceci, car elles peuvent avoir des implications sur les données des utilisateurs. En particulier, une demande est contrôlée en amont si:

Il utilise des méthodes autres que GET, HEAD ou POST. De plus, si POST est utilisé pour envoyer des données de requête avec un Content-Type autre que application / x-www-form-urlencoded, multipart / form-data ou text / plain, par exemple si la requête POST envoie une charge XML au serveur en utilisant application / xml ou text / xml, la demande est alors contrôlée en amont. Il définit des en-têtes personnalisés dans la demande (par exemple, la demande utilise un en-tête tel que X-PINGOTHER)

Réf: AJAX dans Chrome envoi OPTIONS au lieu de GET / POST / PUT / DELETE?

Asim KT
la source
-8

Pour moi, l'extrait explicatif suivant a fonctionné. Peut-être que vous ne devriez pas utiliser 'pour le nom d'en-tête?

{
   headers: { 
      Authorization: "Basic " + getAuthDigest(), 
      Accept: "text/plain" 
   }
}

J'utilise $http.ajax(), même si je ne m'attendrais pas à ce que cela change la donne.

ŁukaszBachman
la source