Comment étendre la classe HTTP angular 2 dans Angular 2 final

J'essaie d'étendre la classe HTTP angular 2 pour pouvoir gérer les erreurs globales et configurer les en-têtes pour mon service secureHttp. J'ai trouvé quelques solutions mais cela ne fonctionne pas avec la version finale D'Angular 2. Il y a mon code:

Fichier: secureHttp.service.ts

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

@Injectable()
export class SecureHttpService extends Http {

  constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
    super(backend, defaultOptions);
  }
}

Fichier: app.module.ts

    import { BrowserModule, Title } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { routing } from './app.routes';
import { AppComponent } from './app.component';
import { HttpModule, Http, XHRBackend, RequestOptions } from '@angular/http';
import { CoreModule } from './core/core.module';
import {SecureHttpService} from './config/secure-http.service'

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    CoreModule,
    routing,
    HttpModule,
  ],
  providers: [
    {
      provide: Http,
      useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => {
        return new SecureHttpService(backend, defaultOptions);
      },
      deps: [ XHRBackend, RequestOptions]
    }, Title, SecureHttpService],
  bootstrap: [AppComponent],
})
export class AppModule { }

Composant.ts

constructor(private titleService: Title, private _secure: SecureHttpService) {}

  ngOnInit() {
    this.titleService.setTitle('Dashboard');
    this._secure.get('http://api.example.local')
        .map(res => res.json())
        .subscribe(
            data =>  console.log(data) ,
            err => console.log(err),
            () => console.log('Request Complete')
        );
  }

Pour l'instant, il me renvoie une erreur ' Aucun fournisseur pour ConnectionBackend!'. Merci pour l'aide!

24
demandé sur mezhik91 2016-09-24 14:28:24

6 réponses

La raison de l'erreur est parce que vous essayez de fournir SecureHttpService

providers: [SecureHttpService]

Cela signifie que Angular va essayer de créer l'instance, Pas en utilisant votre usine. Et il n'a pas de fournisseur enregistré avec le jeton ConnectionBackend à donner à votre constructeur.

Vous pouvez supprimer le SecureHttpService du providers, mais cela vous donnera une autre erreur (ce qui, je suppose, explique pourquoi vous l'avez ajouté en premier lieu). L'erreur sera quelque chose comme " aucun fournisseur pour SecureHttpService " parce que vous essayez de l'injecter dans votre constructeur

constructor(private titleService: Title, private _secure: SecureHttpService) {}

Voici où vous devez comprendre les jetons. Ce que vous fournissez comme valeur à provide est le jeton .

{
  provide: Http,
  useFactory: ()
}

, Le jeton est ce que nous sommes autorisés à injecter. Donc, vous pouvez à la place injecter le Http et il utilisera Votre Créé SecureHttpService. Mais cela vous enlèvera toute chance d'utiliser le Http régulier, si vous en avez besoin.

constructor(private titleService: Title, private _secure: Http) {}

Si vous n'avez pas besoin pour savoir quoi que ce soit sur le SecureHttpService, alors vous pouvez le laisser comme ceci.

Si vous voulez pouvoir injecter le type SecureHttpService (peut-être que vous en avez besoin ou peut-être que vous voulez pouvoir utiliser le Http normal ailleurs), alors changez simplement le provide

{
  provide: SecureHttpService,
  useFactory: ()
}

Maintenant, vous pouvez injecter à la fois le Http régulier et votre SecureHttpService. Et n'oubliez pas de retirer le SecureHttpService du providers.

22
répondu Paul Samsotha 2016-09-24 12:20:58

Découvrez mon article sur la façon d'étendre la classe Http Angulaire 2.1.1

Tout d'abord, permet de créer notre classe de fournisseur http personnalisé.

http.service.ts

import {Injectable} from '@angular/core';
import {Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

@Injectable()
export class HttpService extends Http {

  constructor (backend: XHRBackend, options: RequestOptions) {
    let token = localStorage.getItem('auth_token'); // your custom token getter function here
    options.headers.set('Authorization', `Bearer ${token}`);
    super(backend, options);
  }

  request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {
    let token = localStorage.getItem('auth_token');
    if (typeof url === 'string') { // meaning we have to add the token to the options, not in url
      if (!options) {
        // let's make option object
        options = {headers: new Headers()};
      }
      options.headers.set('Authorization', `Bearer ${token}`);
    } else {
    // we have to add the token to the url object
      url.headers.set('Authorization', `Bearer ${token}`);
    }
    return super.request(url, options).catch(this.catchAuthError(this));
  }

  private catchAuthError (self: HttpService) {
    // we have to pass HttpService's own instance here as `self`
    return (res: Response) => {
      console.log(res);
      if (res.status === 401 || res.status === 403) {
        // if not authenticated
        console.log(res);
      }
      return Observable.throw(res);
    };
  }
}

Maintenant, nous devons configurer notre module principal pour fournir le XHRBackend à notre classe http personnalisée. Dans votre déclaration de module principal, ajoutez ce qui suit au tableau providers:

App.module.ts

import { HttpModule, RequestOptions, XHRBackend } from '@angular/http';
import { HttpService } from './services/http.service';
...
@NgModule({
  imports: [..],
  providers: [
    {
      provide: HttpService,
      useFactory: (backend: XHRBackend, options: RequestOptions) => {
        return new HttpService(backend, options);
      },
      deps: [XHRBackend, RequestOptions]
    }
  ],
  bootstrap: [ AppComponent ]
})

Après cela, vous pouvez maintenant utiliser votre fournisseur http personnalisé dans vos services. Pour exemple:

Utilisateur.service.ts

import { Injectable }     from '@angular/core';
import {HttpService} from './http.service';

@Injectable()
class UserService {
  constructor (private http: HttpService) {}

  // token will added automatically to get request header
  getUser (id: number) {
    return this.http.get(`/users/${id}`).map((res) => {
      return res.json();
    } );
  }
}
21
répondu Adones Pitogo 2016-11-07 03:24:26

Je pense que la réponse de peeskillet devrait être la réponse sélectionnée, donc ce que je mets ici est seulement destiné à augmenter sa réponse plutôt que de rivaliser avec elle,mais je voulais aussi fournir un exemple concret car je ne pense pas que ce soit 100% évident exactement ce que la réponse de peeskillet traduit.

Je mets ce qui suit dans la section providers de mon app.module.ts. J'appelle mon remplacement Http personnalisé MyHttp.

Remarquez comment, comme l'a dit peeskillet, ce serait provide: Http, pas provide: MyHttp.

  providers: [
    AUTH_PROVIDERS
    {
      provide: Http,
      useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => {
        return new MyHttp(backend, defaultOptions);
      },
      deps: [XHRBackend, RequestOptions]
    }
  ],

Alors ma classe Http-extending est définie comme ceci:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';

@Injectable()
export class MyHttp extends Http {
  get(url: string, options?: any) {
    // This is pointless but you get the idea
    console.log('MyHttp');
    return super.get(url, options);
  }
}

Rien de spécial doit être fait pour que votre application pour utiliser MyHttp au lieu de Http.

3
répondu Jason Swett 2017-05-23 12:18:23

À partir D'Angular 4.3, nous n'avons plus besoin de extends http. Au lieu de cela, nous pouvons utiliser HttpInterceptor et HttpClient pour archiver tous ces éléments.

Il est similaire et plus facile que d'utiliser Http.

J'ai migré vers HttpClient en environ 2 heures.

Détail est ici

2
répondu Frank Nguyen 2017-12-26 09:38:19

Vous pouvez vérifier https://www.illucit.com/blog/2016/03/angular2-http-authentication-interceptor/, qui va vous aider.

Changez vos fournisseurs comme ci-dessous pour la dernière version et vérifiez-la:

providers: [
  {
    provide: SecureHttpService,
    useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => {
      return new SecureHttpService(backend, defaultOptions);
    },
    deps: [ XHRBackend, RequestOptions]
  },
  Title
]
0
répondu ranakrunal9 2017-04-13 04:58:50

Vous pouvez simplement étendre le Http dans votre propre classe et ensuite utiliser une usine personnalisée pour fournir Http comme ceci:

Ensuite, dans mes fournisseurs D'applications, j'ai pu utiliser une usine personnalisée pour fournir 'Http'

Import { RequestOptions, Http, Xhrbackend} depuis '@ angular / http';

class HttpClient extends Http {
 /*
  insert your extended logic here. In my case I override request to
  always add my access token to the headers, then I just call the super 
 */
  request(req: string|Request, options?: RequestOptionsArgs): Observable<Response> {

      options = this._setCustomHeaders(options);
      // Note this does not take into account where req is a url string
      return super.request(new Request(mergeOptions(this._defaultOptions,options, req.method, req.url)))
    }

  }
}

function httpClientFactory(xhrBackend: XHRBackend, requestOptions: RequestOptions): Http {

  return new HttpClient(xhrBackend, requestOptions);
}

@NgModule({
  imports:[
    FormsModule,
    BrowserModule,
  ],
  declarations: APP_DECLARATIONS,
  bootstrap:[AppComponent],
  providers:[
     { provide: Http, useFactory: httpClientFactory, deps: [XHRBackend, RequestOptions]}
  ],
})
export class AppModule {
  constructor(){

  }
}

Avec cette approche, vous n'avez pas besoin de remplacer la fonction Http que vous ne souhaitez pas modifier

0
répondu jonnie 2017-05-22 10:59:47