假设我有一些返回可观察值的操作。
this.loginService
.post<IResponse>(url, { username, password })
.subscribe(
next => { /* I know the type of next */ },
error => { /* Can I specify type of err, or is it always any? */ }
);
next
的类型是我可以设置的 - 在本例中为IResponse
。
error
怎么样 - 我可以以某种方式指定它的类型吗?或者它总是any
,并且我总是需要在处理程序中进行类型转换?
根据我的经验,从 HTTP 操作生成可观察值的服务永远不应该发出未捕获的 HTTP 错误。它在该服务的使用者中创建了大量样板代码,并迫使使用者处理 HTTP 特定问题。
我还认为服务不应该捕获所有类型的错误,而应该捕获已知和预期的错误。要求应用程序本身使用错误拦截器处理边缘情况。
export interface ILoginResponse {
//...
}
export interface IServiceResponse<TType> {
success: boolean;
payload?: TType;
}
@Injectable()
export class LoginService {
public login(options: any): Observable<IServiceResponse<ILoginResponse>> {
return this.httpClient.post<ILoginResponse>('login', options).pipe(
map(payload => ({success: true, payload})),
catchError(err => {
if(err instanceof HttpErrorResponse) {
// handle http errors here, maybe retry, update headers, etc..
return of({success: false});
}
// this error is unexpected, we don't know what to do
// let the app interceptor handle it, but upstream observables
// won't know what to do either. Our app has crashed...
// You can return success false, but why handle this error?
return throwError(err);
});
}
}
为什么要执行上述操作?
每当您使用发出未捕获错误的
route解析器时,它都会导致fail路由转换。路由器基本上会崩溃。用户基本上只会看到一个空白页面,因为解析器没有错误处理回退。
上面仅捕获 HTTP 错误,因为这是我们认为应该抛出的唯一类型。另一种错误应该被视为错误。如果组件调用此服务,则程序员应在
信任
发出的值之前检查
success
标志是否为
true
。如果业务逻辑不关心它是否失败,或者组件可以直观地向用户显示它无法执行 HTTP 请求,则可以对此进行过滤。无论哪种方式,HTTP 错误响应都不会发送到应用程序错误拦截器。
这只是一种方法。人们以不同的方式处理 HTTP 事务。另一个答案正确回答了你的问题。
this.loginService
.post<IResponse>(url, { username, password })
.subscribe(
(next: TypeOfYourResponse) => {...},
(error: TypeOfYourErrorResponse) => {...}
);
https://www.tutorialsteacher.com/typescript/arrow-function
https://basarat.gitbooks.io/typescript/docs/arrow-functions.html
subscribe()
以来采用超过 1 个参数的所有
v6.4
签名,因此需要如下所示:
this.loginService
.post<IResponse>(url, { username, password })
.subscribe({
next: (response: TypeOfYourResponse) => {...},
error: (err: TypeOfYourErrorResponse) => {...}
});
this.loginService
.post<IResponse>(url, { username, password })
.catchError<TypeOfYourErrorResponse>(() => // Your catch callback)
.subscribe(
next => { /* I know the type of next */ },
);
我喜欢这样一个事实:它会让消费者在必须检查成功状态时思考错误!然而,有时消费者可能希望从服务器获取并显示错误,所以我对其进行了一些更改:
// DON'T FORGET THESE!
import { Observable, of } from "rxjs";
import { catchError, map } from "rxjs/operators";
export interface ILoginResponse {
//...
}
export interface IServiceResponse<TType> {
payload?: TType;
error?: HttpErrorResponse;
}
@Injectable()
export class LoginService {
public login(options: any): Observable<IServiceResponse<ILoginResponse>> {
return this.httpClient.post<ILoginResponse>('login', options).pipe(
map(payload => ({ payload })),
catchError(err => of({ error: err }))
}
}
不需要成功标志,只需检查是否有有效负载或错误
loginService.login().subscribe(response => {
if (response.payload) {
// success...
}
else if (response.error) {
// handle the error
}
},
我认为返回所有错误,客户可能不关心,因此可以忽略它,但如果他们关心的话,它就会存在;如果您想处理特定错误,请在其他地方使用 HttpInterceptor
...