En mi proyecto Angular 2, hago llamadas a API desde servicios que devuelven un Observable. El código de llamada luego se suscribe a este observable. Por ejemplo:
getCampaigns(): Observable<Campaign[]> {
return this.http.get('/campaigns').map(res => res.json());
}
Digamos que el servidor devuelve un 401. ¿Cómo puedo detectar este error globalmente y redirigir a una página / componente de inicio de sesión?
Gracias.
Esto es lo que tengo hasta ahora:
// boot.ts
import {Http, XHRBackend, RequestOptions} from 'angular2/http';
import {CustomHttp} from './customhttp';
bootstrap(AppComponent, [HTTP_PROVIDERS, ROUTER_PROVIDERS,
new Provider(Http, {
useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => new CustomHttp(backend, defaultOptions),
deps: [XHRBackend, RequestOptions]
})
]);
// customhttp.ts
import {Http, ConnectionBackend, Request, RequestOptions, RequestOptionsArgs, Response} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
@Injectable()
export class CustomHttp extends Http {
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
super(backend, defaultOptions);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
console.log('request...');
return super.request(url, options);
}
get(url: string, options?: RequestOptionsArgs): Observable<Response> {
console.log('get...');
return super.get(url, options);
}
}
El mensaje de error que recibo es "backend.createConnection no es una función"
Respuestas:
Descripción
La mejor solución que he encontrado es anular el
XHRBackend
estado de respuesta HTTP401
y403
conduce a una acción en particular.Si maneja su autenticación fuera de su aplicación Angular, podría forzar una actualización de la página actual de modo que se active su mecanismo externo. Detallo esta solución en la implementación a continuación.
También puede reenviar a un componente dentro de su aplicación de modo que su aplicación Angular no se recargue.
Implementación
Angular> 2.3.0
Gracias a @mrgoos, aquí hay una solución simplificada para angular 2.3.0+ debido a una corrección de errores en angular 2.3.0 (consulte el problema https://github.com/angular/angular/issues/11606 ) que extiende directamente el
Http
módulo.El archivo del módulo ahora solo contiene el siguiente proveedor.
Otra solución que utiliza Router y un servicio de autenticación externo se detalla en la siguiente esencia de @mrgoos.
Angular pre-2.3.0
La siguiente implementación funciona para
Angular 2.2.x FINAL
yRxJS 5.0.0-beta.12
.Redirige a la página actual (más un parámetro para obtener una URL única y evitar el almacenamiento en caché) si se devuelve un código HTTP 401 o 403.
con el siguiente archivo de módulo.
fuente
catch()
no se encontró. (smh)import "rxjs/add/operator/catch";
http
? El único beneficio que veo es que puede simplemente ponerlo como proveedor:{ provide: XHRBackend, useClass: AuthenticationConnectionBackend }
mientras que al anular Http necesita escribir un código más incómodouseFactory
y limitarse llamando a 'nuevo' y enviando argumentos específicos. WDYT? Una referencia al segundo método: adonespitogo.com/articles/angular-2-extending-http-providerAngular 4.3+
Con la introducción de HttpClient vino la capacidad de interceptar fácilmente todas las solicitudes / respuestas. El uso general de HttpInterceptors está bien documentado , consulte el uso básico y cómo proporcionar el interceptor. A continuación se muestra un ejemplo de un HttpInterceptor que puede manejar errores 401.
Actualizado para RxJS 6+
RxJS <6
fuente
Router
aquí no parece funcionar. Por ejemplo, quiero dirigir a mis usuarios a la página de inicio de sesión cuando obtienen un 401-403, perothis.router.navigate(['/login']
no me funciona. No hace nadaimport 'rxjs/add/operator/do';
después de importar rxjs.Como las API frontend caducan más rápido que la leche, con Angular 6+ y RxJS 5.5+, debe usar
pipe
:Actualización para Angular 7+ y rxjs 6+
fuente
error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable<HttpEvent<any>>'.
cuando el.pipe
está allí, no hay errores cuando.pipe
req
es en realidadrequest
: la edición esEl
Observable
que obtiene de cada método de solicitud es de tipoObservable<Response>
. ElResponse
objeto tiene unastatus
propiedad que mantendrá el401
SI el servidor devolvió ese código. Por lo tanto, es posible que desee recuperarlo antes de asignarlo o convertirlo.Si desea evitar hacer esta funcionalidad en cada llamada, es posible que tenga que extender la
Http
clase de Angular 2 e inyectar su propia implementación que llama a parent (super
) para laHttp
funcionalidad regular y luego manejar el401
error antes de devolver el objeto.Ver:
https://angular.io/docs/ts/latest/api/http/index/Response-class.html
fuente
Angular 4.3+
Para completar The Gilbert Arenas Dagger, responde:
Si lo que necesita es interceptar cualquier error, aplicarle un tratamiento y reenviarlo por la cadena (y no solo agregar un efecto secundario con
.do
), puede usar HttpClient y sus interceptores para hacer algo por el estilo:fuente
Para evitar el problema de la referencia cíclica que es causado por la inyección de servicios como "Router" en una clase derivada de Http, se debe utilizar el método Injector post-constructor. El siguiente código es una implementación funcional de un servicio Http que redirige a la ruta de inicio de sesión cada vez que una API REST devuelve "Token_Expired". Tenga en cuenta que se puede utilizar como una sustitución del Http normal y, como tal, no requiere cambiar nada en los componentes o servicios ya existentes de su aplicación.
app.module.ts
extendido-http.service.ts
fuente
Desde Angular> = 2.3.0 puede anular el
HTTP
módulo e inyectar sus servicios. Antes de la versión 2.3.0, no podía usar sus servicios inyectados debido a un error central.He creado una esencia para mostrar cómo se hace.
fuente
app.module
código? Gracias.HTTP
algún otro lugar?Angular> 4.3: ErrorHandler para el servicio base
fuente