angular - Angular & RxJS:如何管理从服务到组件的错误
问题描述
我有一个旨在向 Rest 服务器发送请求的 ApiService。它被多个 ComponentServices 用于从/向服务器检索和发送数据
例如:UsernewComponent 和 UserlistComponent 使用使用 apiService 的 userService。
我想将错误从服务传输到最终组件,以便在发生错误时能够显示模式或其他内容。
但我不会管理它...
谢谢您的帮助 !注意:因为我是 Angular 和 Rxjs 的新手,如果你在我的代码中看到可以更好的东西,请告诉我 ;-)
api.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { throwError } from 'rxjs';
import { map, catchError, timeout } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class ApiService {
private baseEndpoint = 'http://myurl/projserver/api/';
private maxTime = 5000;
constructor(private httpClient: HttpClient) { }
public getEntriesFromRest (option: string): any {
return this.httpClient.get<any[]>(this.baseEndpoint + option)
.pipe(
timeout(this.maxTime),
catchError(this.handleError),
map((data) => data['hydra:member'])
);
}
public getEntryFromRest (option: string): any {
return this.httpClient.get<any>(this.baseEndpoint + option)
.pipe(
timeout(this.maxTime),
catchError(this.handleError)
);
}
handleError(error: HttpErrorResponse) {
let errorMessage = 'Unknown error!';
if (error.error instanceof ErrorEvent) {
// Client-side errors
errorMessage = `Error: ${error.error.message}`;
} else {
// Server-side errors
errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
}
return throwError(errorMessage);
}
}
用户服务.ts
import { User } from '../models/User.model';
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { ApiService } from './api.service';
import { throwError } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UserService {
private users: User[] = [];
private usersSubject = new Subject<User[]>();
usersSubject$ = this.usersSubject.asObservable();
private user: User;
private userSubject = new Subject<User>();
userSubject$ = this.userSubject.asObservable();
constructor(private apiService: ApiService) { }
emitUsers() {
this.usersSubject.next(this.users.slice());
}
emitUser() {
this.userSubject.next(this.user);
}
addUser(user: User) {
this.users.push(user);
this.emitUsers();
}
editUser(user: User) {
var index = this.users.findIndex((item) => item.id === user.id);
this.users.splice(index, 1, user);
this.emitUsers();
}
getUsersFromRest() {
this.users=[];
this.apiService.getEntriesFromRest('users').subscribe(
(data: any[]) => { data.forEach( (item: User) => {
this.users.push(item);});
this.emitUsers();
},
(error) => {
console.log('UserService: '+error);
this.userSubject.next(error);
return throwError(error);
});
}
getUserFromRest(userId: number) {
this.apiService.getEntryFromRest('users/'+userId).subscribe(
(data: User) => {
this.user=data;
this.emitUser();
},
(error) => {
console.log('UserService: '+error);
this.userSubject.next(error);
return throwError(error);
}
);
}
}
usernew.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormArray, FormControl } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';
import { User } from '../../../models/User.model';
import { Role } from '../../../models/Role.model';
import { UserService } from '../../../services/user.service';
import { MustMatch } from '../../../validators/must-match.validator';
import { NbDialogService } from '@nebular/theme';
import { DialogComponent } from '../../../components/dialog/dialog.component';
@Component({
selector: 'usernew',
templateUrl: './usernew.component.html',
styleUrls: ['./usernew.component.scss']
})
export class UsernewComponent implements OnInit, OnDestroy {
userIdSubscription: Subscription;
userSubscription: Subscription;
user: User;
...
constructor(private formBuilder: FormBuilder,
private userService: UserService,
private router: Router,
private route: ActivatedRoute,
private nbDialogService: NbDialogService
) { }
ngOnInit() {
this.initForm();
this.userSubscription = this.userService.userSubject$.subscribe(
(user: User) => {
if (user) {
this.user = user;
this.editUser(this.user);
}
},
(error) => {
console.log('Component: '+error);
}
);
this.userIdSubscription = this.route.paramMap.subscribe(params => {
const userId = +params.get('id'); //cast to number
if(userId) {
this.view='Edit';
this.loading = true;
this.userService.getUserFromRest(userId);
}
});
}
ngOnDestroy() {
this.userIdSubscription.unsubscribe();
this.userSubscription.unsubscribe();
}
...
}
userlist.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { Router, ActivatedRoute } from '@angular/router';
import { User } from '../../../models/User.model';
import { UserService } from '../../../services/user.service';
@Component({
selector: 'userlist',
templateUrl: './userlist.component.html',
styleUrls: ['./userlist.component.scss']
})
export class UserlistComponent implements OnInit, OnDestroy {
...
users: User[] = [];
usersSubscription: Subscription;
loading = false;
constructor(
private userService: UserService,
private router: Router,
private route: ActivatedRoute,
) { }
ngOnInit() {
this.usersSubscription = this.userService.usersSubject$.subscribe(
(users: User[]) => {
this.users = users;
this.loading = false;
},
(error) => {
console.log("Userlist Component: "+error);
}
);
this.loading = true;
this.userService.getUsersFromRest();
//this.userService.emitUsers();
}
ngOnDestroy() {
this.usersSubscription.unsubscribe();
}
...
}
解决方案
您实现ApiService
了为所有 http 调用提供一些常见行为: - 超时 - 错误处理
没关系,但您仍然必须记住在您的每一项其他服务中使用此服务。另外,您仍然必须处理“真实”服务中的错误。
我建议您使用 toHttpInterceptor
来实现这种常见行为。您可以在这里找到一些有价值的信息:https ://medium.com/angular-in-depth/top-10-ways-to-use-interceptors-in-angular-db450f8a62d6
推荐阅读
- node.js - 在 plesk 黑曜石上安装撇号CMS,npm 路径出错
- c# - 如何在 WPF C# 中使用数据绑定?
- php - 避免访问基于 WooCommerce 地理定位国家/地区的特定产品
- apache-camel - Infinispan 问题将 Camel 应用程序从独立移植到 camel-quarkus
- visual-studio-code - 如何在 vscode webview 中加载自定义 CSS
- php - WooCommerce、代码片段和 WPML:允许来自新国家/地区的翻译
- azure - Azure 发布管道 - 如何设置代理池
- javascript - 纯JS中表格元素的下一个/上一个按钮
- python - 为什么这个语句不起作用,我已经导入了数学库
- flutter - Flutter Snackbar 更新状态