сообщение об ошибке fakebackend interceptor: «Имя пользователя« undefined »уже занято» - PullRequest
1 голос
/ 04 октября 2019

Я слежу за этим учебным пособием по реализации простой функции регистрации / входа с помощью перехватчика fakebackend. Пока что я только что создал компонент регистрации, пользовательскую модель и сервис с соответствующими конечными точками, соответствующими поддельному API. Но когда я отправляю учетные данные на сервер, я получаю эту ошибку: error: {message: "Username "undefined" is already taken"}, как будто никакие учетные данные вообще не были отправлены ...

Fakebackend:

    ...The imports...

// array in local storage for registered users
    let users = JSON.parse(localStorage.getItem('users')) || [];

    @Injectable()
    export class FakeBackendInterceptor implements HttpInterceptor {
        intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
            const { url, method, headers, body } = request;

            // wrap in delayed observable to simulate server api call
            return of(null)
                .pipe(mergeMap(handleRoute))
                .pipe(materialize()) // call materialize and dematerialize to ensure delay even if an error is thrown (https://github.com/Reactive-Extensions/RxJS/issues/648)
                .pipe(delay(500))
                .pipe(dematerialize());

            function handleRoute() {
                switch (true) {
                    case url.endsWith('/users/register') && method === 'POST':
                        return register();
                    case url.endsWith('/users/authenticate') && method === 'POST':
                        return authenticate();
                    case url.endsWith('/users') && method === 'GET':
                        return getUsers();
                    case url.match(/\/users\/\d+$/) && method === 'GET':
                        return getUserById();
                    case url.match(/\/users\/\d+$/) && method === 'DELETE':
                        return deleteUser();
                    default:
                        // pass through any requests not handled above
                        return next.handle(request);
                }
            }

            // route functions

            function register() {
                const user = body

                if (users.find(x => x.username === user.username)) {
                    return error('Username "' + user.username + '" is already taken')
                }

                user.id = users.length ? Math.max(...users.map(x => x.id)) + 1 : 1;
                users.push(user);
                localStorage.setItem('users', JSON.stringify(users));

                return ok();
            }

            function authenticate() {
                const { username, password } = body;
                const user = users.find(x => x.username === username && x.password === password);
                if (!user) return error('Username or password is incorrect');
                return ok({
                    id: user.id,
                    username: user.username,
                    firstName: user.firstName,
                    lastName: user.lastName,
                    token: 'fake-jwt-token'
                })
            }

            function getUsers() {
                if (!isLoggedIn()) return unauthorized();
                return ok(users);
            }

            function getUserById() {
                if (!isLoggedIn()) return unauthorized();

                const user = users.find(x => x.id == idFromUrl());
                return ok(user);
            }

            function deleteUser() {
                if (!isLoggedIn()) return unauthorized();

                users = users.filter(x => x.id !== idFromUrl());
                localStorage.setItem('users', JSON.stringify(users));
                return ok();
            }

            // helper functions

            function ok(body?) {
                return of(new HttpResponse({ status: 200, body }))
            }

            function unauthorized() {
                return throwError({ status: 401, error: { message: 'Unauthorised' } });
            }

            function error(message) {
                return throwError({ error: { message } });
            }

            function isLoggedIn() {
                return headers.get('Authorization') === 'Bearer fake-jwt-token';
            }

            function idFromUrl() {
                const urlParts = url.split('/');
                return parseInt(urlParts[urlParts.length - 1]);
            }
        }
    }

    export const fakeBackendProvider = {
        // use fake backend in place of Http service for backend-less development
        provide: HTTP_INTERCEPTORS,
        useClass: FakeBackendInterceptor,
        multi: true
    };

Компонент SignUp:

ngOnInit() {
    this.registerForm = this.fb.group({
      firstName: ['', Validators.required],
      lastName: ['', Validators.required],
      userName: ['', Validators.required],
      password: [null,[ Validators.required, Validators.minLength(6)]]
    })
  }

  get firstName() { return this.registerForm.get('firstName') }
  get lastName() { return this.registerForm.get('lastName') }
  get userName() { return this.registerForm.get('userName') }
  get password() { return this.registerForm.get('password') }

  onSubmit() {
    if (this.registerForm.invalid) return;
      this.userService.register(this.registerForm.value).subscribe(
        data => {
           console.log(data)
        },
        error => {
           console.log(error)
        });

  }

А сервис:

constructor(private http: HttpClient) { }

   register(credentials){
    console.log(credentials)
    return this.http.post(`/users/register`, credentials)
  }

А это снимок консоли

snapshot

Я не реализовал все функции, например службу сообщений, но у меня вопрос: почему я получаю этот ответ от бэкэнда? Разве я не должен получить 200 ставов, так как функция регистрации настроена на это? Примечание: модуль app.module настроен правильно, так как fakebackend зарегистрирован. Также, если я пытаюсь получить пользователей с этой настройкой, я получаю 401, что правильно, потому что я не вошел в систему, поэтому перехватчик работает. Кто-нибудь может мне помочь?

1 Ответ

1 голос
/ 04 октября 2019

В вашей форме вы используете userName, тогда как в перехватчике вы проверяете username. Если вы очистите свой localStorage в браузере, вы, вероятно, заметите, что в первый раз он работает! Почему ...?

Хорошо, поэтому ваш массив в первый раз будет пустым:

let users = JSON.parse(localStorage.getItem('users')) || [];

, поэтому, если вы введете имя пользователя test, ваша полезная нагрузка будет выглядеть как ...

{ userName: 'test' }

ЗАМЕЧАНИЕ в верхнем регистре N .... так что это проходит:

if (users.find(x => x.username === user.username)) {
  return error('Username "' + user.username + '" is already taken');
}

, так как изначально массив пуст.

Затем вы делаете это:

 user.id = users.length ? Math.max(...users.map(x => x.id)) + 1 : 1;
 users.push(user);
 localStorage.setItem("users", JSON.stringify(users));

, поэтому то, что вы сейчас сохранили в users, равно

[{userName: 'test'}]

Теперь это не пройдет во второй раз! Поскольку find теперь будет сравнивать undefined с undefined, так как свойство username не существует ни в одном из объектов, которые вы сравниваете в find .... и undefined === undefined является правдивым, и поэтому вернетПервый элемент в массиве users.

Измените сравнение на:

if (users.find(x => x.userName === user.userName))

, и оно будет работать правильно. Oooooor изменить имя элемента управления формы на username ...

...