如果HTTP GET请求未返回数据,如何保护路由?

时间:2019-06-25 10:22:39

标签: angular typescript angular-guards

以下是我的Angular应用中的表格。它用来自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 }
];

有人可以告诉我实现此功能需要做哪些更改?

3 个答案:

答案 0 :(得分:1)

对于CanActivate后卫来说,这是绝佳的机会。

自Angular 7.1.0起,路由守卫现在可以返回URLTree,这为我们的守卫提供了非常酷的灵活性。 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'

此外,由于您仍然希望对无效的网址使用“全包”格式,因此您可能希望使用类似

的路由
{ 
  path: '**', 
  redirectTo: 'page-not-found'
}

那么这是如何工作的?

它看起来很复杂,但实际上它非常简单。神奇之处在于我们添加到后卫的canActivate()方法中:

我们正在从employeeService请求员工资料,并使用double-not运算符将其转换为布尔值(基本上,检查“我们是否有匹配的员工资料”)。如果将其转换为false,则返回URLTree,它将把路由器重定向到指定的绝对路由。

当解决任何路线时,Angular将以预定义的顺序遍历所有与之相连的防护装置。如果警卫的任何“失败”,则不会加载该路由。

答案 1 :(得分:0)

您可以修改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)
    );
}

答案 2 :(得分:0)

将下面的路由添加到AppRouting模块

{path: '404', component: NotFoundComponent},
{path: '**', redirectTo: '/404'}

上述路由还将在根级和任何嵌套子级中捕获不正确的路由。将此路径作为路由模块中的最后一条路径

如果记录计数为0或为空,则从gotoHeroes方法中调用getEmployee方法

gotoHeroes() {
  this.router.navigate(['/404']);
}