Cómo extender la clase http angular 2 en Angular 2 final


Estoy tratando de extender la clase http angular 2 para poder manejar errores globales y configurar encabezados para mi servicio secureHttp. He encontrado algunas soluciones, pero no funciona con la versión final de Angular 2. Ahí está mi código:

Archivo: secureHttp.Servicio.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);
  }
}

Archivo: app.módulo.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 { }

Componente.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')
        );
  }

Por ahora me devuelve un error ' No provider for ConnectionBackend!'. Gracias por la ayuda!

Author: mezhik91, 2016-09-24

6 answers

La razón del error es porque usted está tratando de proporcionar SecureHttpService

providers: [SecureHttpService]

Lo que esto significa es que Angular intentará crear la instancia, no usando su fábrica. Y no tiene un proveedor registrado con el token ConnectionBackend para darle a su constructor.

Podrías eliminar el SecureHttpService del providers, pero eso te dará otro error (que supongo que es por lo que lo agregaste en primer lugar). El error será algo así como " ningún proveedor para SecureHttpService " porque está tratando de inyectarlo en su constructor

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

Aquí es donde usted necesita entender acerca de los tokens. Lo que usted proporciona como el valor a providees el token .

{
  provide: Http,
  useFactory: ()
}

El token es lo que se nos permite inyectar. Así que puedes inyectar el Http y usará tu creado SecureHttpService. Pero esto le quitará cualquier oportunidad que tenga de usar el Http regular, si alguna vez lo necesita.

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

Si no necesitas para saber algo sobre el SecureHttpService, entonces puedes dejarlo así.

Si desea poder inyectar realmente el tipo SecureHttpService (tal vez necesite alguna API de él o tal vez desee poder usar el Http normal en otro lugar), simplemente cambie el provide

{
  provide: SecureHttpService,
  useFactory: ()
}

Ahora puede inyectar tanto el Http normal como el SecureHttpService. Y no olvides quitar el SecureHttpService del providers.

 22
Author: Paul Samsotha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-24 12:20:58

Echa un vistazo a mi artículo sobre cómo extender la clase Http para Angular 2.1.1

Primero, vamos a crear nuestra clase de proveedor http personalizada.

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

Ahora, necesitamos configurar nuestro módulo principal para proporcionar el XHRBackend a nuestra clase http personalizada. En su declaración de módulo principal, agregue lo siguiente a la matriz de proveedores:

App.módulo.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 ]
})

Después de eso, ahora puede usar su proveedor http personalizado en sus servicios. Para ejemplo:

Usuario.Servicio.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
Author: Adones Pitogo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-07 03:24:26

Creo que la respuesta de peeskillet debería ser la respuesta seleccionada, así que lo que estoy poniendo aquí solo tiene la intención de aumentar su respuesta en lugar de competir con ella, pero también quería proporcionar un ejemplo concreto ya que no creo que sea 100% obvio exactamente a qué código se traduce la respuesta de peeskillet.

Pongo lo siguiente en la sección providers de mi app.module.ts. Estoy llamando a mi reemplazo personalizado Http MyHttp.

Observe cómo, como dijo peeskillet, sería provide: Http, no provide: MyHttp.

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

Entonces mi clase Http-extending se define así:

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

No es necesario hacer nada especial para que tu aplicación use MyHttp en lugar de Http.

 3
Author: Jason Swett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:23

Desde Angular 4.3, ya no necesitamos extends http. En su lugar, podemos usar HttpInterceptor y HttpClient para archivar todas estas cosas.

Es similar y más fácil que usar Http.

Migré a HttpClient en aproximadamente 2 horas.

El detalle es aquí

 2
Author: Frank Nguyen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-26 09:38:19

Puede comprobar https://www.illucit.com/blog/2016/03/angular2-http-authentication-interceptor / que te ayudará.

Cambie sus proveedores como se muestra a continuación para la última versión y compruébelo :

providers: [
  {
    provide: SecureHttpService,
    useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => {
      return new SecureHttpService(backend, defaultOptions);
    },
    deps: [ XHRBackend, RequestOptions]
  },
  Title
]
 0
Author: ranakrunal9,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-13 04:58:50

En realidad puede extender el Http en su propia clase y luego el único uso de una fábrica personalizada para proporcionar Http como eso:

Luego, en mis proveedores de aplicaciones, pude usar una fábrica personalizada para proporcionar 'Http'

Importa {RequestOptions, Http, XHRBackend} desde '@ 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(){

  }
}

Con este enfoque no es necesario anular ninguna de las funciones Http que no desea cambiar

 0
Author: jonnie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-22 10:59:47