Em meu projeto Angular 2, faço chamadas de API de serviços que retornam um Observable. O código de chamada então se inscreve neste observável. Por exemplo:
getCampaigns(): Observable<Campaign[]> {
return this.http.get('/campaigns').map(res => res.json());
}
Digamos que o servidor retorne um 401. Como posso detectar esse erro globalmente e redirecionar para uma página / componente de login?
Obrigado.
Aqui está o que tenho até agora:
// 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);
}
}
A mensagem de erro que estou recebendo é "backend.createConnection is not a function"
Respostas:
Descrição
A melhor solução que encontrei é substituir o de
XHRBackend
modo que o status de resposta HTTP401
e403
leve a uma ação específica.Se você manipular sua autenticação fora de seu aplicativo Angular, poderá forçar uma atualização da página atual de forma que seu mecanismo externo seja acionado. Eu detalho essa solução na implementação abaixo.
Você também pode encaminhar para um componente dentro de seu aplicativo de forma que seu aplicativo Angular não seja recarregado.
Implementação
Angular> 2.3.0
Graças a @mrgoos, aqui está uma solução simplificada para angular 2.3.0+ devido a uma correção de bug no angular 2.3.0 (consulte o problema https://github.com/angular/angular/issues/11606 ) estendendo diretamente o
Http
módulo.O arquivo do módulo agora contém apenas o seguinte provedor.
Outra solução usando roteador e um serviço de autenticação externa é detalhada na essência a seguir por @mrgoos.
Angular pré-2.3.0
A implementação a seguir funciona para
Angular 2.2.x FINAL
eRxJS 5.0.0-beta.12
.Ele redireciona para a página atual (mais um parâmetro para obter um URL exclusivo e evitar o armazenamento em cache) se um código HTTP 401 ou 403 for retornado.
com o seguinte arquivo de módulo.
fonte
catch()
não foi encontrada. (smh)import "rxjs/add/operator/catch";
http
? O único benefício que vejo é que você pode simplesmente colocá-lo como um provedor:{ provide: XHRBackend, useClass: AuthenticationConnectionBackend }
enquanto ao substituir o Http, você precisa escrever um código mais estranhouseFactory
e se limitar chamando 'novo' e enviando argumentos específicos. WDYT? Uma referência ao segundo método: adonespitogo.com/articles/angular-2-extending-http-providerAngular 4.3+
Com a introdução do HttpClient, veio a capacidade de interceptar facilmente todas as solicitações / respostas. O uso geral de HttpInterceptors está bem documentado , consulte o uso básico e como fornecer o interceptor. Abaixo está um exemplo de um HttpInterceptor que pode lidar com erros 401.
Atualizado para RxJS 6+
RxJS <6
fonte
Router
aqui não parece funcionar. Por exemplo, desejo direcionar meus usuários para a página de login quando eles obtiverem um 401-403, masthis.router.navigate(['/login']
não está funcionando para mim. Não faz nadaimport 'rxjs/add/operator/do';
depois de importar rxjs.Como APIs de front-end expiram mais rápido do que leite, com Angular 6+ e RxJS 5.5+, você precisa usar
pipe
:Atualização para Angular 7+ e rxjs 6+
fonte
error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable<HttpEvent<any>>'.
quando o.pipe
está lá, sem erros quando removo o.pipe
req
érequest
- a edição é pequenaO que
Observable
você obtém de cada método de solicitação é do tipoObservable<Response>
. OResponse
objeto, possui umastatus
propriedade que irá reter o401
IF o servidor retornou aquele código. Portanto, você pode querer recuperá-lo antes de mapeá-lo ou convertê-lo.Se você quiser evitar fazer essa funcionalidade em cada chamada, pode ter que estender a
Http
classe de Angular 2 e injetar sua própria implementação dela que chama o pai (super
) para aHttp
funcionalidade regular e, em seguida, manipular o401
erro antes de retornar o objeto.Vejo:
https://angular.io/docs/ts/latest/api/http/index/Response-class.html
fonte
Angular 4.3+
Para completar a resposta da Adaga Gilbert Arenas :
Se o que você precisa é interceptar qualquer erro, aplique um tratamento a ele e encaminhe-o para baixo na cadeia (e não apenas adicione um efeito colateral
.do
), você pode usar o HttpClient e seus interceptadores para fazer algo do tipo:fonte
Para evitar o problema de referência cíclica causado por serviços como "Roteador" sendo injetados em uma classe derivada de Http, deve-se usar o método Injetor pós-construtor. O código a seguir é uma implementação funcional de um serviço Http que redireciona para a rota de Login sempre que uma API REST retorna "Token_Expired". Observe que ele pode ser usado como uma substituição para o Http normal e, como tal, não requer a alteração de nada nos componentes ou serviços já existentes do seu aplicativo.
app.module.ts
extendido-http.service.ts
fonte
Em Angular> = 2.3.0, você pode substituir o
HTTP
módulo e injetar seus serviços. Antes da versão 2.3.0, você não podia usar seus serviços injetados devido a um bug principal.Eu criei uma ideia geral para mostrar como isso é feito.
fonte
app.module
código? Obrigado.HTTP
outro lugar?Angular> 4.3: ErrorHandler para o serviço de base
fonte