Расширить HTTP-перенаправление при возврате несанкционированного доступа

Я пытаюсь перенаправить на страницу входа, когда получаю статус 401 http. Первая попытка была:

public getPatients(extraHttpRequestParams?: any): Observable<Array<models.Patient>> {
const path = this.basePath + '/api/patient';

let queryParameters = new URLSearchParams();
let headerParams = this.defaultHeaders;
let requestOptions: RequestOptionsArgs = {
    method: 'GET',
    headers: headerParams,
    search: queryParameters
};

return this.httpInterceptor.request(path, requestOptions)
    .map((response: Response) => {
        if (response.status === 204) {
            return undefined;
        } else {
            if (response.status === 401) {
                this.router.navigate(['/login']);
            }
            return response.json();
        }
    });

}

Но когда я получаю 401, я не захожу в функцию карты, выдает несанкционированную ошибку в браузере.

Итак, читая некоторые сообщения, есть способ расширить службу http, кажется, это правильный способ, но у меня возникают некоторые проблемы, когда я пытаюсь создать экземпляр http-зависимостей на app.module.ts. В моем случае мне нужно только переписать метод перехватчика, но я помещаю весь код, если кому-то еще нужна другая часть.

Вот мое http-расширение:

import { Http, Request, RequestOptionsArgs, Response, XHRBackend, RequestOptions, ConnectionBackend, Headers} from '@angular/http';
import { Router } from '@angular/router';
import { LocationStrategy, HashLocationStrategy} from '@angular/common';
import { Observable } from 'rxjs/Observable';
import {Injectable} from '@angular/core';

@Injectable()
export class HttpInterceptor extends Http {

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

    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.request(url, options));
    };

    get(url: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.get(url, options));
    };

    post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.post(url, body, this.getRequestOptionArgs(options)));
    };

    put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.put(url, body, this.getRequestOptionArgs(options)));
    };

    delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.delete(url, options));
    };

    getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs {
        if (options == null) {
            options = new RequestOptions();
        }
        if (options.headers == null) {
            options.headers = new Headers();
        }
        options.headers.append('Content-Type', 'application/json');
        return options;
    };

    intercept(observable: Observable<Response>): Observable<Response> {
        return observable.catch((err, source) => {
            if (err.status == 401) {
                this._router.navigate(['/login']);
                return Observable.empty();
            } else {
                return Observable.throw(err);
            }
        });

    }
};

В моем app.module.ts я должен добавить это:

import { NgModule } from '@angular/core';
import { BrowserModule }  from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { routing, appRoutingProviders } from './app.routing';
import { FormsModule }    from '@angular/forms';
import { Routes, RouterModule }   from '@angular/router';
import { HomeComponent } from './home/home.component';
import { PatientsComponent } from './pacientes/pacientes.component';
import { HttpInterceptor }  from '../api/api/HttpInterceptor';
import { RequestOptions, ConnectionBackend} from '@angular/http';
import { HttpModule, JsonpModule } from '@angular/http';
const routes: Routes = [

];

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    JsonpModule,
    routing,
    RouterModule.forRoot(routes, { useHash: true }),  // .../#/crisis-center/
  ],
  declarations: [
    AppComponent,
    PatientsComponent,
  ],
  providers: [
    appRoutingProviders,
    HttpInterceptor,
    RequestOptions 
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

На данный момент все хорошо, но когда я пытаюсь использовать новую службу httpInterceptor, которую я создал, импортирую ее и добавляю в конструктор и заменяю экземпляр http для моего нового экземпляра http-перехватчика, я получаю Нет провайдера для ConnectionBackend, я пытаюсь добавить ConnectionBackend к провайдерам, но он говорит, что «типы провайдеров свойств несовместимы». Затем я пытаюсь добавить httpInterceptor, но получаю сообщение об ошибке Uncaught: не удается разрешить все параметры для RequestOptions: (?).

Таким образом, должен быть способ правильно расширить метод http или обработать 401 по-другому. Как я могу это сделать, есть ли какое-то руководство, ссылка или что-то еще, чтобы взглянуть?


person Diego Unanue    schedule 15.09.2016    source источник
comment
Какую версию Angular вы используете?   -  person Paul Samsotha    schedule 15.09.2016
comment
Я использую версию rc6   -  person Diego Unanue    schedule 15.09.2016


Ответы (1)


Нет провайдера, зарегистрированного с токеном ConnectionBackend. Что вы можете сделать, так это использовать фабрику при настройке перехватчика.

providers:    [
  { 
    provide: HttpInterceptor,
    useFactory: (backend: XHRBackend, options: RequestOptions, router: Router) => {
      return new HttpInterceptor(backend, options, router);
    },
    deps: [XHRBackend, RequestOptions, Router ]
  }
]

Я проверил это с вашим кодом, и он должен работать.

person Paul Samsotha    schedule 16.09.2016
comment
Я использую http для отправки запроса, но мне нужно создать экземпляр этого нового http HttpInterceptor и вместо этого.http.request... я использую this.http.httpInterceptor. Я думал, что использование этой фабрики не потребует замены http для моего HttpInterceptor, что он просто будет использовать его. Есть ли способ не заменять и указывать angular всегда использовать мой HttpInterceptor? - person Diego Unanue; 19.09.2016
comment
Используйте 1_ - person Paul Samsotha; 19.09.2016
comment
Если это все еще не работает (он все еще использует обычный Http), то вам, вероятно, нужно избавиться от импорта HttpModule и самостоятельно предоставить все зависимости, от которых зависит Http. Вы можете посмотреть источник для HttpModule - person Paul Samsotha; 19.09.2016
comment
Вы имеете в виду это? провайдеры: [ { обеспечить: Http, useFactory: (серверная часть: XHRBackend, параметры: RequestOptions, маршрутизатор: маршрутизатор) => { вернуть новый HttpInterceptor (серверная часть, параметры, маршрутизатор); }, deps: [XHRBackend, RequestOptions, Router] } ] Когда я это делаю, он говорит, что не является провайдером для HttpInterceptor - person Diego Unanue; 19.09.2016
comment
Разве вы не пытаетесь использовать Http, а не HttpInterceptor? provide предоставляет токен, для которого вы можете выполнить инъекцию. Если вы измените его на Http, вы больше не сможете вводить HttpInterceptor. Но фактический объект Http все равно должен быть вашим пользовательским перехватчиком, потому что это то, что вы возвращаете с фабрики. - person Paul Samsotha; 19.09.2016
comment
Да, я использую http вместо httpInterceptor в своих вызовах this.http.request(path, requestOptions)....., но кажется, что по-прежнему нужен встроенный шаблон провайдера: 0:0, вызванный: Нет провайдера для HttpInterceptor . - person Diego Unanue; 19.09.2016
comment
Убедитесь, что вы нигде не пытаетесь внедрить HttpInterceptor. Вы должны только попытаться ввести Http - person Paul Samsotha; 19.09.2016