我试图使用解析器来制作更好的用户体验。在快乐的道路上,一切都很美好。我似乎无法弄清楚如何处理异常。我的解析器调用一个服务,该服务命中webapi项目。一个例子:
FooResolver:
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Foo> {
return this.fooService.getById(route.params['id']).catch(err => {
****not sure what to do/return in the case of a server error****
return Observable.throw(err);
});
}
FooService接口
public getById(id: string): Observable<Foo> {
return this.http.get(`${ this.apiUrl }/${ id }`)
.map(this.extractData)
.catch(this.handleError);
}
handleError函数:
protected handleError (error: Response | any) {
// Todo: Log the error
// Errors will be handled uniquely by the component that triggered them
return Observable.throw(error);
}
在FooComponent内部,我执行此操作(如果从服务/解析程序返回错误,则永远不会命中此内容):
FooComponent :
ngOnInit(): void {
this.foo= this.route.snapshot.data['foo'];
if (this.foo) {
this.createForm(this.foo);
}
}
我尝试抛出错误(如图所示) - 我在控制台中收到此异常:
未捕获(承诺):状态响应:500内部服务器错误 对于URL:
并返回new Observable<Foo>()
,其中包含:
无法阅读财产&#39;订阅&#39;未定义的
我有一些解析器,所有这些都可以在服务器上遇到异常,但我不知道在发生这些异常时该怎么做。
答案 0 :(得分:38)
以下是我的一个处理错误的解析器的示例,使用了Gunter建议的技术:
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/of';
import { IProduct } from './product';
import { ProductService } from './product.service';
@Injectable()
export class ProductResolver implements Resolve<IProduct> {
constructor(private productService: ProductService,
private router: Router) { }
resolve(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<IProduct> {
let id = route.params['id'];
if (isNaN(+id)) {
console.log(`Product id was not a number: ${id}`);
this.router.navigate(['/products']);
return Observable.of(null);
}
return this.productService.getProduct(+id)
.map(product => {
if (product) {
return product;
}
console.log(`Product was not found: ${id}`);
this.router.navigate(['/products']);
return null;
})
.catch(error => {
console.log(`Retrieval error: ${error}`);
this.router.navigate(['/products']);
return Observable.of(null);
});
}
}
您可以在此处找到完整的示例:https://github.com/DeborahK/Angular-Routing在APM-final文件夹中。
2019年2月更新
以下是解析器中错误处理的更好答案:
1)使用可选的错误属性将您的界面包装在另一个界面中:
/* Defines the product entity */
export interface Product {
id: number;
productName: string;
productCode: string;
category: string;
tags?: string[];
releaseDate: string;
price: number;
description: string;
starRating: number;
imageUrl: string;
}
export interface ProductResolved {
product: Product;
error?: any;
}
2)解析到该界面:
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { ProductResolved } from './product';
import { ProductService } from './product.service';
@Injectable({
providedIn: 'root'
})
export class ProductResolver implements Resolve<ProductResolved> {
constructor(private productService: ProductService) { }
resolve(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<ProductResolved> {
const id = route.paramMap.get('id');
if (isNaN(+id)) {
const message = `Product id was not a number: ${id}`;
console.error(message);
return of({ product: null, error: message });
}
return this.productService.getProduct(+id)
.pipe(
map(product => ({ product: product })),
catchError(error => {
const message = `Retrieval error: ${error}`;
console.error(message);
return of({ product: null, error: message });
})
);
}
}
3)在组件中,拉下您需要的界面:
ngOnInit(): void {
const resolvedData: ProductResolved =
this.route.snapshot.data['resolvedData'];
this.errorMessage = resolvedData.error;
this.product = resolvedData.product;
}
答案 1 :(得分:9)
您需要返回一个以<?php
class Example {
function bar(): iterable{
return [1, 2, 3];
}
function gen(): iterable {
yield 1;
yield 2;
yield 3;
}
}
$obj=new Example();
print $obj->gen();
print $obj->bar();
false
答案 2 :(得分:0)
我只想提供一个非常相似的更新答案,但带有一些更新代码。我个人认为错误不应该在解析器内部进行管理。
为什么?好吧,我认为解析器的工作是解决问题,而不是弄清楚如果无法解决该怎么办。我们可能在两个或三个不同的组件中使用此解析器,如果解析器发生故障,它们每个都可能决定以不同的方式做出反应。我们可能想将其中一个重定向到404页面,但是在其他情况下,我们可能只是尝试通过显示其他内容来修复错误。
当然,我们可能还想根据遇到的错误做出不同的反应:可能是用户未获得授权,或者该项目已被删除,或者甚至根本不存在(知道)。我们可能希望显示不同的结果,在这种情况下,我完全支持 DeborahK 的更新答案。但是对于大多数情况,我认为这会使问题变得过于复杂(仅用于解析器的一个额外接口,确保其中的错误是描述性的……),我们很可能不会真正在意解析器为什么会失败:它只是做了,让需要该项目的组件会弄清楚该做什么,然后继续。
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/internal/operators';
import { Product } from '../_interfaces';
import { ProductsService } from '../_services';
@Injectable()
export class ProductResolver implements Resolve<Product> {
constructor(private productsService: ProductsService) {
}
public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
const id = route.paramMap.get('id');
return this.productsService.getProduct(id).pipe(
catchError(error => {
console.error(`Can't resolve product with id ${id} because of the error:`);
console.error(error);
return of(null);
})
);
}
}