Ioni c angular два HTTP-запроса, ждущие друг друга - PullRequest
0 голосов
/ 25 мая 2020

У меня есть auth.service.ts с переменной HttpClient, загруженной из конструктора с методом вызова моего API, чтобы получить информацию о пользователе и его привилегиях, а также есть ли у него действующий токен. Он работает нормально. Но на некоторых страницах я вызываю api, чтобы получить исходные данные для этой страницы. На этих страницах у меня есть переменная HttpClient, определенная из конструктора. Если я вызываю два запроса почти одновременно, один из ответов каждый раз оказывается пустым.

У меня есть RequestModel класс, в котором я реализовал HTTP-запросы:

export class RequestModel {  
  private errors: string[];
  private responseData: any;
  private requestData: any;
  private loading: any;
  private url: string;
  private type: RequestType;

  constructor(private authService: AuthService, private http: HttpClient, private loadingController: LoadingController) {}

  async request(callback: () => void) {
    await this.presentLoading();
    this.prepareDataRequest()
        .pipe(
            finalize(async () => {
              await this.loading.dismiss();
            })
        )
        .subscribe(
            data => {
              this.responseData = data;
              if(this.responseData && this.responseData.token) this.authService.setToken(this.responseData.token);
              console.log(this.responseData);
              callback();
            },
            err => {
              this.errors = ["An error occurred, the data could not be retrieved: Status: " + err.status + ", Message: " + err.statusText];
            }
        );
  }

  async presentLoading() {
    this.loading = await this.loadingController.create({
      message: 'Loading...'
    });
    await this.loading.present();
  }

  private prepareDataRequest(): Observable<object> {
    var dataUrl = environment.apiEndpoint + this.url;
    const config = { headers: new HttpHeaders({'Content-Type': 'application/json; charset=utf-8', 'Authorization': 'Bearer ' + this.authService.getToken()}) };

    if (this.type == RequestType.DELETE) return this.http.delete(dataUrl, config);
    else if (this.type == RequestType.HEAD) return this.http.head(dataUrl, config);
    else if (this.type == RequestType.OPTIONS) return this.http.options(dataUrl, config);
    else if (this.type == RequestType.PATCH) return this.http.patch(dataUrl, this.requestData, config);
    else if (this.type == RequestType.POST) return this.http.post(dataUrl, this.requestData, config);
    else if (this.type == RequestType.PUT) return this.http.put(dataUrl, this.requestData, config);
    else if (this.type == RequestType.GET) return this.http.get(dataUrl, config);
    else {
      this.errors = ["Unsuported request type."];
      return;
    }
  }
}

У меня есть auth.service.ts , где я вызываю api для проверки аутентификации пользователя перед загрузкой страницы.

export class AuthService {
  api: RequestModel;
  userType = UserType.NULL;
  user = null;
  userId = null;
  private token = null;

  constructor(
    private storage: Storage, 
    private platform: Platform, 
    private helper: JwtHelperService, 
    private router: Router, 
    private http: HttpClient, 
    private loadingController: LoadingController
    ) {
    this.api = new RequestModel(this, http, loadingController);
    this.onAuthorizationCheckResponse = this.onAuthorizationCheckResponse.bind(this);
    this.authorizationCheck();
    this.loadToken();
    this.platform.ready().then(() => {
    });
  }

  onAuthorizationCheckResponse() {
    var response = this.api.getResponseData();
    if(response && response.token) {
      this.storage.set(TOKEN_KEY, response.token);
      this.token = response.token;
      this.userId = response.userId;
      if(response.data) {
        this.user = response.data;
        this.userType = response.data.idUserType;
        if(this.userType == UserType.USER || this.userType == UserType.ADMIN) window.dispatchEvent(new CustomEvent('isLoggedIn:true'));
        else window.dispatchEvent(new CustomEvent('isLoggedIn:false'));
      }
      else window.dispatchEvent(new CustomEvent('isLoggedIn:false'));
    }
  }

  loadToken(){
    this.storage.get(TOKEN_KEY).then(token => {
      if (token) {
        //let decoded = this.helper.decodeToken(token);
        this.token = token;
      }
    });
  }

  getToken(){
    if(!this.token) this.loadToken();
    return this.token;
  }

  setToken(token){
    if(this.token != token) {
      this.token = token;
      this.storage.set(TOKEN_KEY, token);
    }
  }

  removeToken(){
    this.storage.remove(TOKEN_KEY);
    this.token = null;
    this.userType = UserType.NULL;
    this.user = null;
    //this.authorizationCheck();
  }

  authorization(responseData){
    if(responseData.token){
      this.setToken(responseData.token);
      this.user = responseData.user;
    }
  }

  authentification(responseData){
    if(responseData.token){
      this.setToken(responseData.token);
    }
  }

  async authorizationCheck(){
    this.api.setUrl("login/check");
    this.api.setType(RequestType.GET);
    await this.api.request(this.onAuthorizationCheckResponse);
  }
}

Это пример одной страницы, на которой я вызываю запрос на загрузку данных:

export class QuickMatchPage implements OnInit {
  api: RequestModel;
  matchModel: MatchModel;
  isActive: boolean = false;
  isCreator: boolean = false;

  constructor(
    private authService: AuthService,
    private http: HttpClient,
    private loadingController: LoadingController,
    private alertController: AlertController,
    private router: Router
  ) {
    this.api = new RequestModel(authService, http, loadingController);
    this.matchModel = new MatchModel();
    this.onBeginMatchResponse = this.onBeginMatchResponse.bind(this);
    this.matchCheckResponse = this.matchCheckResponse.bind(this);
    this.onCreateMatchResponse = this.onCreateMatchResponse.bind(this);
    this.onCancelResponse = this.onCancelResponse.bind(this);
  }

  ngOnInit() {    
  }

  ionViewWillEnter(){
    this.matchCheck();
  }

  async matchCheck(){
    this.api.setUrl("match/check");
    this.api.setType(RequestType.GET);
    await this.api.request(this.matchCheckResponse);
  }

  async matchCheckResponse(){
    if(this.api.getResponseData().success) {
      if(this.api.getResponseData().data) {
        this.matchModel.fromObject(this.api.getResponseData().data);
        this.matchModel.convertToInputAttributes();
        this.isActive = true;
        if(this.api.getResponseData().data.idMatchState == MatchState.RUNNING) this.router.navigateByUrl("visitor/quick-match/running");
        if(this.api.getResponseData().data.idUser == this.authService.userId) this.isCreator = true;
      }
    }
    else {
      this.isActive = false;
      this.isCreator = false;
      const alert = await this.alertController.create({
        header: "Alert",
        message: this.api.getResponseData().message,
        buttons: ["OK"]
      });

      await alert.present();
    }
  }
}

После ionWillEnter тех же страниц я вызываю другой HTTP-запрос для получения текущих данных. Пример ответа: Но очень часто второй запрос отправляется до того, как я получу ответ от первого, и поэтому я получаю это из ответа api: I не знаю, что мне делать. Я попытался реализовать Observable, чтобы дождаться изменения значения userId, но когда-нибудь, когда приложение попадает в ionWillEnter, userId уже загружен, и я больше не буду его менять. Я думаю, что целые логи c делать это неправильно. Плохая практика. Несколько советов, как это сделать лучше и один запрос ждет другого? Или какая-то проверка условий, прежде чем я позвоню другому запросу или что-то в этом роде, может быть. Я не знаю.

Конечно, у меня нет этой проблемы, когда пользователь запускает страницу, где мне нужно только проверить аутентификацию и ничего более, а затем go на страницу, где мне нужно загрузить некоторые данные из api.

...