我正在遵循这个tutorial来实现一个带有假后端拦截器的简单注册/登录功能。到目前为止,我已经构建了注册组件,用户模型和服务,并具有与虚假API匹配的相应端点。但是,当我将凭据发送到服务器时,出现以下错误:error: {message: "Username "undefined" is already taken"}
,好像根本没有凭据被发送一样……
假后端:
...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
};
注册组件:
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)
}
这是控制台的一个亮点
例如,我尚未实现所有功能,例如消息服务,但是我的问题是,为什么我会从后端得到此响应?寄存器功能设置为可以使我得到200个stauts吗?注意:由于假后端已注册,因此正确设置了app.module。另外,如果我尝试通过此设置获取用户,则会得到401,这是正确的,因为我尚未登录,因此拦截器正在工作。有人可以帮我吗?
答案 0 :(得分:1)
在表单中,您正在使用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
中比较的两个对象中都不存在。...和{ {1}}是真实的,因此它将返回您的undefined === undefined
数组中的第一项。
将您的比较更改为:
users
,它将正常工作。哦,将表单控件名称更改为if (users.find(x => x.userName === user.userName))
...