web-dev-qa-db-fra.com

Angular HttpClient ne définit pas l'en-tête d'autorisation

J'ai vu plusieurs autres questions comme celle-ci, mais elles ne résolvent pas le problème. J'ai utilisé l'API de MailChimp pour effectuer un simple appel afin d'ajouter un membre à ma liste de diffusion lors de leur inscription. 

Cependant, lorsque je teste, je reçois un 401 non autorisé et l'API se plaint de l'absence de clé API. Lorsque j'inspecte la demande dans Chrome, aucun en-tête d'autorisation ne s'affiche. Voici mon code:

        const formData = {
            email_address: this.emailControl.value,
            status: 'subscribed',
            merge_fields: {
                NAME: this.nameControl.value
            }
        };
        const header = new HttpHeaders({
            'Authorization': 'apikey:' + environment.mailChimpApiKey
        });

        this.http.post(this.mailChimpUrl, formData, {
            headers: header,
            observe: 'response'
        }).subscribe(response => {
            console.log('response', response);
            if (response.status === 200) {
                this.submitted = true;
            }
        });

J'ai vérifié et revérifié la signature de la méthode HttpClient.post et la manière dont l'API MailChimp s'attend à recevoir l'en-tête Auth. On dirait que je fais tout bien, alors pourquoi Angular ne met-il pas l'en-tête?

Je remarque que la valeur change uniquement pour le Access-Control-Request-Headers lorsque je définis des en-têtes facultatifs. Est-ce que je lis mal la console chrome?

 enter image description here

Version angulaire: 5.2.4

5
inorganik

Le problème n'est pas avec Angular. Les navigateurs modernes envoient une requête preflight OPTIONS pour la plupart des requêtes entre domaines, ce qui n'est pas pris en charge par Mailchimp. L'API Mailchimp ne prend pas en charge les implémentations côté client:

MailChimp ne prend pas en charge l'implémentation côté client de notre API à l'aide de Demandes de la SCRO en raison du risque potentiel pour la sécurité associé au compte exposé Clés API.

Cela aurait été bien si cela avait été dit un peu plus clairement, mais je ne l'avais pas remarqué au début. La meilleure solution consiste à utiliser jsonp.

3
inorganik

Pour ce faire, nous devons importer Headers et RequestOptions avec Http à partir de la bibliothèque @angular/http.

Et comme @Maciej l'a suggéré, vous pouvez également utiliser withCredentials : true pour les options de votre demande.

ApplicationService.ts

import { Injectable } from '@angular/core';
import { Http, Headers, Response, RequestOptions } from '@angular/http';

@Injectable()
export class ApplicationService {

  constructor(private http: Http) {
  }

  myformPost(id:number, formData : any){

     let header = this.initHeaders();
     let options = new RequestOptions({ headers: header, method: 'post'});
     let body = JSON.stringify(formData);

     return this.http.post(this.myapiUrl, body, options)
                .map(res => {
                    return res.json();
                })
                .catch(this.handleError.bind(this));
  }

  private initHeaders(): Headers {
      var headers = new Headers();
      let token = localstorage.getItem(StorageKey.USER_TOKEN);
      if (token !== null) {
         headers.append('Authorization', token);
      }

      headers.append('Pragma', 'no-cache');
      headers.append('Content-Type', 'application/json');
      headers.append('Access-Control-Allow-Origin', '*');
      return headers;
  }

  private handleError(error: any): Observable<any> {
      return Observable.throw(error.message || error);
  }             
}
1
Amol Bhor

Sur la capture d'écran, je suppose que vous faites une demande OPTIONS et non pas POST.

Probablement le problème est du côté du serveur. Découvrez cette réponse: http post - comment envoyer un en-tête d'autorisation?

Vous devez également envisager d’ajouter withCredentials à vos options de demande.

const formData = {
            email_address: this.emailControl.value,
            status: 'subscribed',
            merge_fields: {
                NAME: this.nameControl.value
            }
        };
        const header = new HttpHeaders({
            'Authorization': 'apikey:' + environment.mailChimpApiKey
        });

        this.http.post(this.mailChimpUrl, formData, {
            headers: header,
            observe: 'response',
            withCredentials: true
        }).subscribe(response => {
            console.log('response', response);
            if (response.status === 200) {
                this.submitted = true;
            }
        });

Selon documentation :

withCredentials: boolean | nul 

Activer les informations d'identification d'utilisation pour une demande.

0
Maciej Treder

Je préférerais beaucoup commenter la réponse originale des affiches, car j'estime qu'elle est correcte et qu'une clarification peut aider cette personne à obtenir +1 pour la réponse.

Alors.. 

Si j'utilise du code entre angular et deux de mes domaines et que j'utilise un noeud pour servir les données, je dois entrer les informations suivantes pendant le développement sur le serveur de noeuds. Je le fais très ouvert au début pour m'assurer que tout fonctionne dans le développement. 

app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, 
PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true); //
next();

});

Cela efface votre erreur mais est trop ouvert pour le cross-scripting, vous pouvez lire comment autoriser des domaines spécifiques, etc., à y accéder au lieu du * fourni ici. 

0
Alex Mackinnon