92 votes

Comment définir le baseUrl pour Angular HttpClient ?

Je n'ai pas trouvé de moyen dans le documentation pour définir l'URL de l'API de base pour les demandes HTTP. Est-il possible de le faire avec le HttpClient d'Angular ?

2 votes

Vous pourriez créer un intercepteur qui mettra à jour l'url avec la base que vous voulez.

1 votes

N'est-ce pas une surcharge que d'utiliser des intercepteurs dans ce cas ?

0 votes

Si vous ne voulez changer que cela, oui, c'est possible. Une autre option serait d'avoir une simple fonction getApiUrl() qui fera toutes les transformations nécessaires, comme l'ajout du chemin de base.

127voto

TheUnreal Points 5776

Utilisez le nouvel intercepteur HttpClient.

Créer un injectable approprié qui implémente HttpInterceptor :

import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class APIInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    const apiReq = req.clone({ url: `your-api-url/${req.url}` });
    return next.handle(apiReq);
  }
}

Le HttpInterceptor peut cloner la requête et la modifier comme vous le souhaitez, dans ce cas j'ai défini un chemin par défaut pour toutes les requêtes http.

Fournissez le HttpClientModule avec les configurations suivantes :

providers: [{
      provide: HTTP_INTERCEPTORS,
      useClass: APIInterceptor,
      multi: true,
    }
  ]

Maintenant, toutes vos requêtes commenceront par your-api-url/

8 votes

C'est génial ! Une chose cependant, vous n'avez pas besoin d'utiliser le décorateur Injectable ici, il est seulement requis lorsque vous voulez injecter quelque chose dans la classe décorée.

6 votes

Et si vous voulez que différents HttpClients utilisent des urls de base différentes, comment gérez-vous cela ? Une sorte de marqueur dans la requête que l'injecteur active, plusieurs injecteurs. Cela ne me semble pas du tout élégant.

51 votes

Je pleure quand je vois ce code. Pourquoi ne pouvons-nous pas simplement créer une instance de client qui a un nom d'utilisateur et un mot de passe ? baseUrl au lieu de cette solution de type intergiciel qui est excessive pour un cas d'utilisation aussi simple.

58voto

Alexei Points 3124

Sur la base de TheUnreal Selon la réponse très utile de l'auteur, l'intercepteur peut être écrit pour obtenir l'url de base via DI :

@Injectable()
export class BaseUrlInterceptor implements HttpInterceptor {

    constructor(
        @Inject('BASE_API_URL') private baseUrl: string) {
    }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        const apiReq = request.clone({ url: `${this.baseUrl}/${request.url}` });
        return next.handle(apiReq);
    }
}

BASE_API_URL peut être fourni par le module d'application :

providers: [
    { provide: "BASE_API_URL", useValue: environment.apiUrl }
]

donde environment est l'objet créé automatiquement par le CLI lors de la génération du projet :

export const environment = {
  production: false,
  apiUrl: "..."
};

1 votes

Où est-ce que vous mettez BASE_API_URL ?

1 votes

@emaillenin - comme il y a plus d'un commentaire, j'ai ajouté les informations dans la réponse. Fondamentalement, la valeur est fournie "globalement".

0 votes

@Alexei que faire si nous avons besoin de consommer 2 BASE_API_URL différentes ? Je veux dire que nous avons un projet et qu'il utilise 2 serveurs API avec des bases différentes.

5voto

moorthi daniel Points 41

Extraits de l'exemple d'application Visual studio 2017 asp.net core webapi angular.

inclure les lignes ci-dessous dans Main.ts

export function getBaseUrl() {
  return document.getElementsByTagName('base')[0].href;
}

const providers = [
  { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] }
];

dans votre composant

  constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
      this.forecasts = result;
    }, error => console.error(error));
  }

mon code main.ts complet ressemble à ce qui suit

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

export function getBaseUrl() {
  return document.getElementsByTagName('base')[0].href;
}

const providers = [
  { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] }
];

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch(err => console.error(err));

mon code de composant ressemble à ce qui suit

import { Component, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'fetch-weather',
  templateUrl: './weather.component.html',
  styleUrls: ['./weather.component.scss']
})

export class WeatherComponent {
  public forecasts: WeatherForecast[];

  constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
      this.forecasts = result;
    }, error => console.error(error));
  }
}

interface WeatherForecast {
  dateFormatted: string;
  temperatureC: number;
  temperatureF: number;
  summary: string;
}

0 votes

C'est une solution assez géniale. Surtout parce qu'elle peut utiliser la fonctionnalité --base-href qu'angular inclut déjà - ce qui rend très facile l'hébergement de l'api + l'application angular dans un sous-dossier.

4voto

skinny_jones Points 211

Vous n'avez pas nécessairement besoin d'un URL de base con HttpClient La documentation indique qu'il suffit de spécifier la partie api de la requête, si vous faites des appels au même serveur, c'est simple comme bonjour :

this.http.get('/api/items').subscribe(data => {...

Toutefois, vous pouvez, si vous le souhaitez ou si vous en avez besoin, spécifier une URL de base.

J'ai deux suggestions pour y parvenir :

1 . Une classe d'aide avec une propriété de classe statique.

export class HttpClientHelper {

    static baseURL: string = 'http://localhost:8080/myApp';
}

this.http.get(`${HttpClientHelper.baseURL}/api/items`); //in your service class

2 . Une classe de base avec une propriété de classe, donc tout nouveau service doit l'étendre :

export class BackendBaseService {

  baseURL: string = 'http://localhost:8080/myApp';

  constructor(){}
}

@Injectable()
export class ItemsService extends BackendBaseService {

  constructor(private http: HttpClient){  
    super();
  }

  public listAll(): Observable<any>{    
    return this.http.get(`${this.baseURL}/api/items`);
  }

}

2voto

Anton Lee Points 596

Je pense qu'il n'y a pas de moyen par défaut de faire cela. Faites le HttpService et à l'intérieur vous pouvez définir la propriété de votre URL par défaut, et faire des méthodes pour appeler http.get et autres avec votre propriété URL. Injectez ensuite HttpService au lieu de HttpClient.

0 votes

Je l'ai fait pour le service Http, mais j'espérais que HttpClient soit un peu plus intelligent

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X