如果 HTTP GET 请求 returns 没有数据,如何保护路由?
How to guard route if HTTP GET request returns no data?
下面是我的 Angular 应用程序中的一个 table。它填充了来自 employees.json
:
的数据
<tbody>
<tr *ngFor="let employee of employees">
<td (click)="viewEmployeeProfile(1, employee.id)">{{employee.fullName}}
</td>
</tr>
</tbody>
当用户点击一个名字时,employeeId
被传递给这个方法:
viewEmployeeProfile(roleId: number, employeeId: number) {
this._router.navigate(['/profile', roleId, employeeId]);
}
这是我的 AppRouting
模块中的路线:
const routes: Routes = [
{
path: 'profile/:role/:id',
component: ProfileComponent,
// canActivate: [RequireEmployeeProfileGuardGuard]
},
{
path: 'page-not-found',
component: PageNotFoundComponent
},
{
path: '**',
component: PageNotFoundComponent
}
];
示例路径:http://localhost:4200/profile/1/4
当用户路由到Profile
组件时,调用这段代码:
profile.component.ts:
ngOnInit() {
this.route.paramMap.subscribe(params => {
const roleId = +params.get('role');
const empId = +params.get('id');
this.getEmployee(empId);
});
}
getEmployee(id: number) {
this.employeeService.getEmployee(id).subscribe(
(employee: IEmployee) => this.displayEmployee(employee),
(err: any) => console.log(err)
);
}
displayEmployee(employee: IEmployee) {
this.employee.fullName = employee.fullName;
}
profile.component.html:
<tr>
<td><b>Full Name</b></td>
<td>{{employee.fullName}}</td>
</tr>
这是我的 employee.service
:
baseUrl = 'http://localhost:3000/employees';
getEmployee(id: number): Observable<IEmployee> {
return this.httpClient.get<IEmployee>(`${this.baseUrl}/${id}`)
.pipe(catchError(this.handleError));
}
此代码运行良好,并按预期显示数据。
目前,如果我导航到 http://localhost:4200/profile/1/123456789
之类的路线,其中 employeeId
不存在,则 Profile
组件显示时没有数据。
相反,我希望将用户带回 PageNotFound
组件。
这是我当前的路线:
const routes: Routes = [
{ path: 'profile/:role/:id', component: ProfileComponent },
{ path: '**', component: PageNotFoundComponent }
];
有人可以告诉我我需要做哪些改变才能实现这个吗?
您可以修改您的 getEmployee
方法来执行类似
getEmployee(id: number) {
this.employeeService.getEmployee(id).subscribe(
(employee: IEmployee) => {
if(employee){
this.displayEmployee(employee)
}else{
//redirect to page not found here
}
},
(err: any) => console.log(err)
);
}
将以下路由添加到 AppRouting
模块
{path: '404', component: NotFoundComponent},
{path: '**', redirectTo: '/404'}
以上路由将在根级别和任何嵌套子级中捕获不正确的路由,因为 well.put 此路径作为路由模块中的最后一个路径
如果记录计数为 0 或 null
,则从 getEmployee
方法调用 gotoHeroes
方法
gotoHeroes() {
this.router.navigate(['/404']);
}
这对 CanActivate 后卫来说是一个绝佳的机会。
自 Angular 7.1.0 以来,路由守卫现在可能 return 一篇 URLTree which gives us some really cool flexibility in our guards. Here 是一篇很好的文章,其中介绍了更改及其含义/如何使用它们。
我建议你创建你的守卫。类似于以下内容:
import { Injectable } from '@angular/core';
import { CanActivate, Router, UrlTree, ActivatedRouteSnapshot } from '@angular/router';
import { Observable, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
// import your employee service here
@Injectable()
export class RequireEmployeeProfileGuard implements CanActivate {
constructor(private router: Router, private employeeService: EmployeeService) {
}
canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> {
return this.employeeService.getEmployee(+route.paramMap.get('id')).pipe(
catchError(() => of(false)),
map(employee => !!employee || this.router.parseUrl('page-not-found'))
);
}
}
从这里,转到你的路由模块,导入这个守卫并将它添加到你的路由中,如下所示:
{
path: 'profile/:role/:id',
component: ProfileComponent,
canActivate: [RequireEmployeeProfileGuard]
}
我也可能会为错误组件定义一个明确命名的路由,例如:
{
path: 'page-not-found',
component: PageNotFoundComponent
}
那么上面守卫的'absolute-redirect-url-here'
就变成了'page-not-found'
.
此外,由于您仍希望对无效 URL 进行 'catch-all' 处理,因此您可能需要这样的路由:
{
path: '**',
redirectTo: 'page-not-found'
}
那么这是如何工作的?
它可能看起来很复杂,但其实它的核心非常简单。神奇之处在于我们添加到守卫的 canActivate()
方法:
我们从 employeeService
请求员工资料,并使用 double-not 运算符将其转换为布尔值(基本上,检查 "do we have a matching employee profile")。如果这转换为 false
,则 URLTree
被 returned,它将路由器重定向到指定的绝对路由。
当任何路由被解析时,Angular 将 运行 以 pre-defined 的顺序通过所有附加到它的守卫。如果 任何 守卫 'fail' 则不会加载该路线。
下面是我的 Angular 应用程序中的一个 table。它填充了来自 employees.json
:
<tbody>
<tr *ngFor="let employee of employees">
<td (click)="viewEmployeeProfile(1, employee.id)">{{employee.fullName}}
</td>
</tr>
</tbody>
当用户点击一个名字时,employeeId
被传递给这个方法:
viewEmployeeProfile(roleId: number, employeeId: number) {
this._router.navigate(['/profile', roleId, employeeId]);
}
这是我的 AppRouting
模块中的路线:
const routes: Routes = [
{
path: 'profile/:role/:id',
component: ProfileComponent,
// canActivate: [RequireEmployeeProfileGuardGuard]
},
{
path: 'page-not-found',
component: PageNotFoundComponent
},
{
path: '**',
component: PageNotFoundComponent
}
];
示例路径:http://localhost:4200/profile/1/4
当用户路由到Profile
组件时,调用这段代码:
profile.component.ts:
ngOnInit() {
this.route.paramMap.subscribe(params => {
const roleId = +params.get('role');
const empId = +params.get('id');
this.getEmployee(empId);
});
}
getEmployee(id: number) {
this.employeeService.getEmployee(id).subscribe(
(employee: IEmployee) => this.displayEmployee(employee),
(err: any) => console.log(err)
);
}
displayEmployee(employee: IEmployee) {
this.employee.fullName = employee.fullName;
}
profile.component.html:
<tr>
<td><b>Full Name</b></td>
<td>{{employee.fullName}}</td>
</tr>
这是我的 employee.service
:
baseUrl = 'http://localhost:3000/employees';
getEmployee(id: number): Observable<IEmployee> {
return this.httpClient.get<IEmployee>(`${this.baseUrl}/${id}`)
.pipe(catchError(this.handleError));
}
此代码运行良好,并按预期显示数据。
目前,如果我导航到 http://localhost:4200/profile/1/123456789
之类的路线,其中 employeeId
不存在,则 Profile
组件显示时没有数据。
相反,我希望将用户带回 PageNotFound
组件。
这是我当前的路线:
const routes: Routes = [
{ path: 'profile/:role/:id', component: ProfileComponent },
{ path: '**', component: PageNotFoundComponent }
];
有人可以告诉我我需要做哪些改变才能实现这个吗?
您可以修改您的 getEmployee
方法来执行类似
getEmployee(id: number) {
this.employeeService.getEmployee(id).subscribe(
(employee: IEmployee) => {
if(employee){
this.displayEmployee(employee)
}else{
//redirect to page not found here
}
},
(err: any) => console.log(err)
);
}
将以下路由添加到 AppRouting
模块
{path: '404', component: NotFoundComponent},
{path: '**', redirectTo: '/404'}
以上路由将在根级别和任何嵌套子级中捕获不正确的路由,因为 well.put 此路径作为路由模块中的最后一个路径
如果记录计数为 0 或 null
,则从getEmployee
方法调用 gotoHeroes
方法
gotoHeroes() {
this.router.navigate(['/404']);
}
这对 CanActivate 后卫来说是一个绝佳的机会。
自 Angular 7.1.0 以来,路由守卫现在可能 return 一篇 URLTree which gives us some really cool flexibility in our guards. Here 是一篇很好的文章,其中介绍了更改及其含义/如何使用它们。
我建议你创建你的守卫。类似于以下内容:
import { Injectable } from '@angular/core';
import { CanActivate, Router, UrlTree, ActivatedRouteSnapshot } from '@angular/router';
import { Observable, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
// import your employee service here
@Injectable()
export class RequireEmployeeProfileGuard implements CanActivate {
constructor(private router: Router, private employeeService: EmployeeService) {
}
canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> {
return this.employeeService.getEmployee(+route.paramMap.get('id')).pipe(
catchError(() => of(false)),
map(employee => !!employee || this.router.parseUrl('page-not-found'))
);
}
}
从这里,转到你的路由模块,导入这个守卫并将它添加到你的路由中,如下所示:
{
path: 'profile/:role/:id',
component: ProfileComponent,
canActivate: [RequireEmployeeProfileGuard]
}
我也可能会为错误组件定义一个明确命名的路由,例如:
{
path: 'page-not-found',
component: PageNotFoundComponent
}
那么上面守卫的'absolute-redirect-url-here'
就变成了'page-not-found'
.
此外,由于您仍希望对无效 URL 进行 'catch-all' 处理,因此您可能需要这样的路由:
{
path: '**',
redirectTo: 'page-not-found'
}
那么这是如何工作的?
它可能看起来很复杂,但其实它的核心非常简单。神奇之处在于我们添加到守卫的 canActivate()
方法:
我们从 employeeService
请求员工资料,并使用 double-not 运算符将其转换为布尔值(基本上,检查 "do we have a matching employee profile")。如果这转换为 false
,则 URLTree
被 returned,它将路由器重定向到指定的绝对路由。
当任何路由被解析时,Angular 将 运行 以 pre-defined 的顺序通过所有附加到它的守卫。如果 任何 守卫 'fail' 则不会加载该路线。