Представление Angular 5 не загружает результат после вызова токена обновления - PullRequest
0 голосов
/ 27 июня 2018

В моем текущем проекте я использую Adal.js с угловым 5 для обработки аутентификации.

Но сейчас у меня довольно странная проблема с http-перехватчиком и данными ответа.

Основная логика моего перехватчика заключается в том, что я попытаюсь выполнить вызов API с помощью кэшированного токена, если произойдет сбой с 401, я получу новый токен и попытаюсь повторить вызов с новым токеном.

Но то, что происходит после второго вызова, мое представление не будет обновлять с какими-либо полученными данными, если я не взаимодействую со страницей каким-либо образом. (щелчок, прокрутка и т. д.)

Любая идея, что может вызвать это и в любом случае это исправить?

1012 * редактировать *

Я только что узнал, что могу внедрить ChangeDetectorRef и обнаружить изменения, которые заставят представление визуализироваться. Мне не понравится это решение, потому что оно будет означать, что каждый вызов API требует обнаружения изменений, что звучит как плохая идея. Есть ли более элегантные решения?

компонент

import { Component, OnInit, Injector } from '@angular/core';
import { AppBaseComponent } from '../../../../global/app-base.component'; 
import { VendorVM } from "../../../../proxy/service-proxies";
import { VendorsService } from '../vendors.service';


@Component({
    selector: 'vendors-list',
    templateUrl: './vendors.list.component.html',
    styleUrls: []
})

export class VendorsListComponent extends AppBaseComponent implements OnInit {
    public vendors: VendorVM[];
    constructor(
        injector: Injector,
        public service: VendorsService) {
        super(injector);
    }
ngOnInit(): void {
    this.getVendors();
}

public getVendors() {
    this.service.getVendorsForList().subscribe(data => {
        this.vendors = data;
        this.vendorsUnfiltered = data;
        console.log('vendors loaded');
        console.log(this.vendors);
    });
  }
}

перехватчик

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpEvent, HttpResponse, HttpErrorResponse, HttpRequest } from '@angular/common/http';
import { AuthService } from '../global/services/auth.service';
import { Observable } from 'rxjs/Observable';
import { AdalService } from './../global/services/adal.service';

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

  constructor(private _auth: AuthService, private adal: AdalService) { }



addToken(request: HttpRequest<any>, token: string): HttpRequest<any> {
    return request = request.clone({
      setHeaders: {
        Authorization: 'Bearer ' + token
      }
    });

  }



public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const authReq = this.addToken(request, this._auth.getToken());
return next.handle(authReq)
  .map((event: HttpEvent<any>) => {
    if (event instanceof HttpResponse) {
      return event;
    }
  })
  .catch((err: any) => {
    console.log('http error');

    if (err instanceof HttpErrorResponse) {
      if (err.status === 401) {
        console.log('401 get new token');

        return this.adal
          .getNewToken()
          .flatMap((res) => {
            console.log(res);

            return next.handle(this.addToken(request, res))
          });

      } else if (err.status === 403) {
        console.log('403', err);
      }
    } else {
      console.log('unknown error', err);
      return Observable.throw(err);
    }
   })
  }
}

Просто чтобы повторить, происходят следующие две вещи.

вызов компонента -> перехватчик -> получить кешированный токен -> авторизацию и выполнить вызов -> успех загружает данные и отображает представление.

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

1 Ответ

0 голосов
/ 21 октября 2018

Застрял с этим целую вечность - закончил тем, что сделал мой собственный вопрос.

Мне наконец удалось найти решение, основанное на этом ответе: Запросы Http, сделанные из состояния Ngxs, не обнаруживаются Angular (проблема, связанная с зоной)

Обернуть следующий дескриптор в ngZone run ():

return this._ngZone.run(() => {
  return next.handle(req).pipe(enterZone(this._ngZone));
});

function enterZone<T>(zone: NgZone) {
  return (source: Observable<T>) => {
    return new Observable((sink: Observer<T>) => {
      return source.subscribe({
        next(x) { zone.run(() => sink.next(x)); },
        error(e) { zone.run(() => sink.error(e)); },
        complete() { zone.run(() => sink.complete()); }
      });
    });
  };
}

Я не уверен, почему функциональность enterZone требуется поверх стандартного метода zone.run (), но он помог мне убедиться, что представление обновляется при возврате из перехватчика.

Подробнее о ngZone читайте здесь: https://angular.io/api/core/NgZone

Учитывая, что httpInterceptor является частью Angular, я не уверен, зачем это нужно.

...