在 Angular 中调用 httpClient.delete() 时无法处理 HTTP/404 8

Unable to handle HTTP/404 when calling httpClient.delete() in Angular 8

调用 DELETE 方法时,我有 returns HTTP/404 的 Springboot 2.1 端点。 有 Angular 8 个应用程序使用 HttpClient 调用该端点。它已被简化为最简单的代码。

如果我调用 httpClient.delete('url').subscribe(); 而后端 returns HTTP/404 我是无法处理错误。 Angular 在控制台中抛出此错误:错误类型错误:您提供了 'undefined' 预期流的位置。您可以提供 Observable、Promise、Array 或 Iterable。

我尝试按照 Angular http 客户端描述中的描述处理错误,但没有帮助。在调用任何错误处理代码之前,Angular 在控制台中抛出错误并且不执行任何错误处理。

这是Java代码

@RestController
@RequestMapping("/api/test")
@RequiredArgsConstructor
class TestController {

  @DeleteMapping("/{id}")
  public ResponseEntity deleteObject(@PathVariable("id") Long id) {
    return ResponseEntity.notFound().build();
  }
}

Angular 调用此端点的代码是:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class ObjectsService {

  constructor(private httpClient: HttpClient) {
  }

  deleteObject() {
    return this.httpClient.delete('http://localhost:8090/api/test/5').subscribe();
  }
}

Chrome 显示响应为:

Request URL: http://localhost:8090/api/test/5
Request Method: DELETE
Status Code: 404 
Remote Address: [::1]:8090
Referrer Policy: no-referrer-when-downgrade

不幸的是,我没有正常执行,而是在控制台中收到错误消息:

ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
    at subscribeTo (subscribeTo.js:27)
    at subscribeToResult (subscribeToResult.js:11)
    at CatchSubscriber.error (catchError.js:38)
    at XMLHttpRequest.onLoad (http.js:2476)
    at ZoneDelegate.invokeTask (zone-evergreen.js:391)
    at Object.onInvokeTask (core.js:39679)
    at ZoneDelegate.invokeTask (zone-evergreen.js:390)
    at Zone.runTask (zone-evergreen.js:168)
    at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:465)
    at invokeTask (zone-evergreen.js:1603)

编辑: 还有正在处理错误的 HTTPInterceptor:

  private handleErrors(err: HttpErrorResponse): Observable<any> {
    if (err.status === 401) {
      this.loginService.redirectToUrl = this.router.url;
      this.router.navigate(['/login']);
      return of(err.message);
    }
  }

感谢@igor,"missing else" 被发现了。在拦截器中添加 HTTP/404 处理解决了这个问题。

您需要在 subscribe() 中传递参数以作为响应。在你的例子中

deleteObject() {
  return this.httpClient.delete('http://localhost:8090/api/test/5').subscribe(response => {
    // Here you will handle response
  }, (error) => {
    // Here you can handle errors
  });
}

如果您需要处理来自所有 API 调用的错误,那么使用通用错误处理程序来处理错误将是一个理想的解决方案。

https://angular.io/api/core/ErrorHandler

有关错误处理程序和拦截器的更多详细信息,

what is the difference between error handler and interceptor in angular 2?

如果未到达在可观察对象上执行的错误处理代码,那么您配置了一个 HttpInterceptor,它在到达此代码之前处理错误。

我想说的一个好的开始是实现拦截器并处理这些错误:

@Injectable()
export class ServiceHttpInterceptor implements HttpInterceptor {

 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
   ...........
   next.handle(req)
            .pipe(tap(event => {
                if (event instanceof HttpResponse) {
                  // doNothing now
                }
            }))
            .pipe(catchError(err => {
                      if (err instanceof HttpErrorResponse) {
                          // Handle your 404 here
                          }
           }
}

}