Обработка 401s по всему миру с помощью углового

В моем проекте Angular 2 я вызываю вызовы API из служб, которые возвращают Observable. Затем вызывающий код присоединяется к этому наблюдаемому. Например:

getCampaigns(): Observable { return this.http.get('/campaigns').map(res => res.json()); } 

Скажем, сервер возвращает 401. Как я могу поймать эту ошибку глобально и перенаправить на страницу / компонент входа?

Благодарю.


Вот что я до сих пор:

// 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 { console.log('request...'); return super.request(url, options); } get(url: string, options?: RequestOptionsArgs): Observable { console.log('get...'); return super.get(url, options); } } 

Сообщение об ошибке, которое я получаю, это «backend.createConnection – не функция»

Описание

Лучшее решение, которое я нашел, это переопределить XHRBackend таким образом, что статус ответа HTTP 401 и 403 приводит к определенному действию.

Если вы обрабатываете аутентификацию вне своего приложения с угловым выражением, вы можете принудительно обновить текущую страницу таким образом, чтобы ваш внешний механизм был запущен. Я подробно описываю это решение в реализации ниже.

Вы также можете переслать компонент внутри своего приложения, чтобы ваше угловое приложение не было перезагружено.

Реализация

Угловое> 2.3.0

Благодаря @mrgoos, это упрощенное решение для углового 2.3.0+ из-за исправления ошибок в угловом 2.3.0 (см. Вопрос https://github.com/angular/angular/issues/11606 ), распространяющегося непосредственно на модуль Http ,

 import { Injectable } from '@angular/core'; import { Request, XHRBackend, RequestOptions, Response, Http, RequestOptionsArgs, Headers } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/catch'; import 'rxjs/add/observable/throw'; @Injectable() export class AuthenticatedHttpService extends Http { constructor(backend: XHRBackend, defaultOptions: RequestOptions) { super(backend, defaultOptions); } request(url: string | Request, options?: RequestOptionsArgs): Observable { return super.request(url, options).catch((error: Response) => { if ((error.status === 401 || error.status === 403) && (window.location.href.match(/\?/g) || []).length < 2) { console.log('The authentication session expires or the user is not authorised. Force refresh of the current page.'); window.location.href = window.location.href + '?' + new Date().getMilliseconds(); } return Observable.throw(error); }); } } 

Файл модуля теперь содержит только следующий провайдер.

 providers: [ { provide: Http, useClass: AuthenticatedHttpService } ] 

Другое решение, использующее маршрутизатор и внешнюю службу проверки подлинности, подробно описано в следующем разделе @mrgoos.

Угловое пред-2.3.0

Следующая реализация работает для Angular 2.2.x FINAL и RxJS 5.0.0-beta.12 .

Он перенаправляет на текущую страницу (плюс параметр, чтобы получить уникальный URL-адрес и избежать кэширования), если возвращается код HTTP 401 или 403.

 import { Request, XHRBackend, BrowserXhr, ResponseOptions, XSRFStrategy, Response } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/catch'; import 'rxjs/add/observable/throw'; export class AuthenticationConnectionBackend extends XHRBackend { constructor(_browserXhr: BrowserXhr, _baseResponseOptions: ResponseOptions, _xsrfStrategy: XSRFStrategy) { super(_browserXhr, _baseResponseOptions, _xsrfStrategy); } createConnection(request: Request) { let xhrConnection = super.createConnection(request); xhrConnection.response = xhrConnection.response.catch((error: Response) => { if ((error.status === 401 || error.status === 403) && (window.location.href.match(/\?/g) || []).length < 2) { console.log('The authentication session expires or the user is not authorised. Force refresh of the current page.'); window.location.href = window.location.href + '?' + new Date().getMilliseconds(); } return Observable.throw(error); }); return xhrConnection; } } 

со следующим файлом модуля.

 import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { HttpModule, XHRBackend } from '@angular/http'; import { AppComponent } from './app.component'; import { AuthenticationConnectionBackend } from './authenticated-connection.backend'; @NgModule({ bootstrap: [AppComponent], declarations: [ AppComponent, ], entryComponents: [AppComponent], imports: [ BrowserModule, CommonModule, HttpModule, ], providers: [ { provide: XHRBackend, useClass: AuthenticationConnectionBackend }, ], }) export class AppModule { } 

Угловой 4.3+

С введением HttpClient появилась возможность легко перехватывать все запросы / ответы. Общее использование HttpInterceptors хорошо документировано , см. Основное использование и как обеспечить перехватчик. Ниже приведен пример HttpInterceptor, который может обрабатывать ошибки 401.

 import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http' import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/do'; @Injectable() export class ErrorInterceptor implements HttpInterceptor { intercept(req: HttpRequest, next: HttpHandler): Observable> { return next.handle(req).do(event => {}, err => { if (err instanceof HttpErrorResponse && err.status == 401) { // handle 401 errors } }); } } 

Observable вы получаете от каждого метода запроса, имеет тип Observable . Объект Response имеет свойство status которое будет содержать 401 если сервер вернет этот код. Поэтому вы можете захотеть получить это, прежде чем сопоставлять его или преобразовывать.

Если вы хотите избежать выполнения этой функции при каждом вызове, вам может потребоваться расширить class Http Angular 2 и внедрить собственную реализацию, которая вызывает родительский ( super ) для обычной функции Http а затем обрабатывает ошибку 401 перед возвратом объекта.

Видеть:

https://angular.io/docs/ts/latest/api/http/index/Response-class.html

Из Angular> = 2.3.0 вы можете переопределить модуль HTTP и ввести свои службы. До версии 2.3.0 вы не могли использовать ваши внедренные службы из-за основной ошибки.

Я создал суть, чтобы показать, как это делается.

Угловой 4.3+

Чтобы закончить кинжал Гилберта Аренаса, ответьте:

Если вам нужно перехватить какую-либо ошибку, примените к ней лечение и переместите его по цепочке (а не просто добавьте побочный эффект с помощью .do ), вы можете использовать HttpClient и его перехватчики, чтобы сделать что-то в этом роде:

 import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/catch'; @Injectable() export class ErrorInterceptor implements HttpInterceptor { intercept(req: HttpRequest, next: HttpHandler): Observable> { // install an error handler return next.handle(req).catch((err: HttpErrorResponse) => { console.log(err); if (err.error instanceof Error) { // A client-side or network error occurred. Handle it accordingly. console.log('An error occurred:', err.error.message); } else { // The backend returned an unsuccessful response code. // The response body may contain clues as to what went wrong, console.log(`Backend returned code ${err.status}, body was: ${err.error}`); } return Observable.throw(new Error('Your custom error')); }); } } 

Чтобы избежать проблемы циклической ссылки, вызванной тем, что в качестве classа «Http-производные» были добавлены такие сервисы, как «Маршрутизатор», следует использовать метод Injector после конструктора. Следующий код представляет собой рабочую реализацию службы Http, которая перенаправляется на маршрут входа каждый раз, когда REST API возвращает «Token_Expired». Обратите внимание, что его можно использовать в качестве замены регулярному Http и, как таковой, не требует изменения чего-либо в уже существующих компонентах или службах вашего приложения.

app.module.ts

  providers: [ {provide: Http, useClass: ExtendedHttpService }, AuthService, PartService, AuthGuard ], 

Угловой> 4.3: ErrorHandler для базовой службы

 protected handleError(err: HttpErrorResponse | any) { console.log('Error global service'); console.log(err); let errorMessage: string = ''; if (err.hasOwnProperty('status')) { // if error has status if (environment.httpErrors.hasOwnProperty(err.status)) { // predefined errors errorMessage = environment.httpErrors[err.status].msg; } else { errorMessage = `Error status: ${err.status}`; if (err.hasOwnProperty('message')) { errorMessage += err.message; } } } if (errorMessage === '') { if (err.hasOwnProperty('error') && err.error.hasOwnProperty('message')) { // if error has status errorMessage = `Error: ${err.error.message}`; } } // no errors, then is connection error if (errorMessage === '') errorMessage = environment.httpErrors[0].msg; // this.snackBar.open(errorMessage, 'Close', { duration: 5000 }}); console.error(errorMessage); return Observable.throw(errorMessage); } 
  • Загрузка файлов с помощью API-интерфейса Angular2 в REST
  • Angularjs2 - предварительная конфигурация сервера перед запуском приложения
  • Angular2: 2 услуги в зависимости друг от друга
  • Проблема с обнаружением изменений. Почему это изменяется, когда это одна и та же ссылка на объект с On Push
  • Скрыть / показать отдельные элементы внутри ngFor
  • FakeAsync гарантирует завершение обещания после tick / flushMicroservice
  • угловое2 наблюдаемое, получение неопределенного в компоненте
  • Как передать данные на угловые маршрутизаторы?
  • CORS и API API Google Maps
  • Как получить ссылку на компонент, связанный с ElementRef в Angular 2
  • Угловые динамические вкладки с выбранными компонентами
  • Давайте будем гением компьютера.