Angular 8 подписаться на финиш нескольких запросов, как? - PullRequest
0 голосов
/ 11 июля 2019

У меня есть служба авторизации с методом входа и компонентом входа.

Из метода onSubmit моих компонентов входа в систему я вызываю метод входа служб и подписываюсь на ответ.

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

компонент входа:

    this.authenticationService.login(this.f.username.value, this.f.password.value)
        .pipe(first())
        .subscribe(
            data => {
                this.router.navigate([this.returnUrl]);
            },
            error => {
                this.alertService.error(error);
                this.loading = false;
            });

служба аутентификации:

    login(username, password) {
        return this.http.post<any>(`${config.apiUrl}/users/authenticate`, { username, password })
            .pipe(map(user => {
                // store user details and jwt token in local storage to keep user logged in between page refreshes
                localStorage.setItem('currentUser', JSON.stringify(user));
                this.currentUserSubject.next(user);
                return user;
            }));
    }

Я пробовал несколько вложенных вызовов, используя http.get (). Pipe и множество вариантов этого, но, очевидно, мне все еще не хватает базовых знаний.

Фрагмент / идеяотсюда: https://jasonwatmore.com/post/2019/06/10/angular-8-user-registration-and-login-example-tutorial


Редактировать:

У меня есть решение, но это уродливо, некоторые улучшения возможны?

return new Observable((observer) => {
    this.http.get<any>(urlToken)
        .pipe(map(answer => {
            if (answer['type'] != 'Success') { return; }

            let token = answer['message'];
            urlLogin += '&passphrase=' + someSalt(username, password, token);

            return this.http.get<any>(urlLogin)
                .pipe(map(answer2 => {
                    if (answer2['type'] != 'Success') { return; }

                    let sessionId = answer2['message'];
                    let user = new User();
                    user.username = username;
                    user.sessionId = sessionId;

                    localStorage.setItem('currentUser', JSON.stringify(user));
                    this.currentUserSubject.next(user);
                    observer.next(user);
                })).subscribe();
        })).subscribe();
});

1 Ответ

2 голосов
/ 12 июля 2019

при последовательном сцеплении наблюдаемых объектов используется концепция, называемая отображением высшего порядка (я предлагаю в этой статье ). Один из этих операторов отображения высшего порядка - concatMap , и объединение его с оператором tap поможет вам правильно достичь поставленных целей. ваше решение не просто безобразно :( оно не тестируемое и не слишком сложное. Ваш метод login должен быть таким;

  login(username, password) {
    /** we use concatmap here because return value of this callback is going to be another observable.
     * we are mapping result of an observable to another obervable. higher-order-mapping ;)
     */
    return this.http.get<any>(urlToken).pipe(concatMap(answer => {
      /** notice that we have to return an observable in concatMap callback, that's why we use `of()` */
      if (answer['type'] != 'Success') { return of(false); }

      let token = answer['message'];
      urlLogin += '&passphrase=' + someSalt(username, password, token);

      /** we use tap here baceuse we are not modifying the response in anyway. we just want to do some
       * side operations without affecting return value of this obervable.
       */
      return this.http.get<any>(urlLogin).pipe(tap(answer2 => {
          /** we just return here beause tap operator is just doing side operations */
          if (answer2['type'] != 'Success') { return; }

          let sessionId = answer2['message'];
          let user = new User();
          user.username = username;
          user.sessionId = sessionId;

          localStorage.setItem('currentUser', JSON.stringify(user));
          this.currentUserSubject.next(user);
          observer.next(user);      
      }));
    }));
  }

вот демонстрация вышеуказанных понятий https://stackblitz.com/edit/angular-qvhay8

...