0

编辑 [04.01.2020]

我发现,string我得到"Bad Request"的是我的错误对象的消息。(未设置消息)。因此,当我更改 API 响应以使消息包含我的实际错误对象时,这很好。

let error = {error: {}, code: '', message: {error: {}, code: ''}};
if (err.code === 'DUPLICATE_ENTRY') {
  error.message.code = 'DUPLICATE_ENTRY';
  error.message.error = {
    columns: ["name"]
  };
}

所以我们可以说,这解决了我的问题,但老实说,这不是我所期望的。我是否遗漏了什么或者这是正确的方法,这应该如何工作?我真的应该将我的实际错误对象放入伪消息块中吗?


技术

我使用 Angular 8 作为前端,使用带有 typeorm 作为 API 的 nest.js 6.12.9。

简短的介绍

问题在于无法解析 Angular 中的 API 响应对象。Angular中的错误只是一个字符串说Bad Request

设置

API 控制器

@Post()
async create(@Query() link: string, @Body() enrollment: Enrollment, @Res() res: Response) {
    this.enrollmentService.create(enrollment, link).then(tEntrollment => {
        delete tEntrollment.appointment;
        res.status(HttpStatus.CREATED).json(tEntrollment);
    }).catch((err) => {
        let id = this.makeid(10);
        console.log(`[${(new Date()).toDateString()} ${(new Date()).toTimeString()}] Code: ${id} - ${err}`);

        let error = {error: {}, code: ''};
        if (err.code === 'ER_DUP_ENTRY') {
            error.code = 'DUPLICATE_ENTRY';
            error.error = {
                columns: ["name"]
            };
        } else {
            error.error = {
                undefined: {
                    message: "Some error occurred. Please try again later or contact the support",
                    code: id
                }
            };
        }

        res.status(HttpStatus.BAD_REQUEST).json(error);
    });
}

在发布一个像

{
  "additions": [],
  "driver": null,
  "passenger": { "requirement": 1 },
  "name": "Test",
  "comment": ""
}

控制器做了,它应该做什么。在这种情况下,该名称Test已被使用,因此该.catch()块处理其余部分,并返回一个错误响应HttpStatus.BAD_REQUEST和对象

{
    "error": {
        "columns": [
            "name"
        ]
    },
    "code": "DUPLICATE_ENTRY"
}

请注意,此对象是通过 Postman 发布调用来获取的。所以这里一切正常。


主要问题

如前所述,问题是,我无法在我的角度项目中得到这个响应。呼叫由我拨打terminService,如下所示。

enroll(enrollment: IEnrollmentModel, appointment: IAppointmentModel): Observable<HttpEvent<IEnrollmentModel>> {
    const url = `${environment.api.url}enrollment?link=${appointment.link}`;
    // const req = new HttpRequest('POST', url, {
    //   data: enrollment,
    //   observe: 'response',
    //   reportProgress: true,
    // });
    // return this.httpClient.request(req);
    return this.httpClient.post<IEnrollmentModel>(url, enrollment, {observe: 'response'});
  }

我的处理方式是ernollment.component.ts这样的

this.terminService.enroll(output, this.appointment).subscribe(result => {
        if (result.type === HttpEventType.Response) {
          switch (result.status) {
            case HttpStatus.CREATED:
              this.router.navigate([`enroll`], {queryParams: {val: this.appointment.link}});
              break;
          }
        }
      }, error => {
        console.log(error)
        switch (error.status) {
          case HttpStatus.BAD_REQUEST:
            if (error.code === 'DUPLICATE_ENTRY') {
              error.error.columns.forEach(fColumn => {
                  const uppercaseName = fColumn.charAt(0).toUpperCase() + fColumn.substring(1);
                  const fnName: string = 'get' + uppercaseName;
                  this[fnName]().setErrors({inUse: true});
              }
            });
            break;
        }
      }
    );

发布的对象看起来与之前显示的完全一样。查看我可以看到的 Chrome 开发工具,此 API 调用的响应与我预期的完全一样。 {"error":{"columns":["name"]},"code":"DUPLICATE_ENTRY"}. 这实际上是一个好兆头,但我无法在 Angular 中得到这个响应。在记录错误时,error => {}我只是得到一个字符串说Bad Request。我也尝试过记录error.status error.body error.error等,但这只是记录undefined,因为错误不是对象。它只是一个字符串。

我错过了什么?如何正确访问和解析响应,包括我的 API 返回的对象和 HttpStatus?

4

3 回答 3

0

Angular HttpClient 在尝试将其解析为 JSON 时似乎会稍微破坏响应。您可以在订阅之前在 Observable 级别捕获原始错误:

yourObservable$.pipe(catchError((error) => console.log(error))).subscribe();
于 2020-01-02T21:29:20.173 回答
0

在您的注册方法中,替换函数返回类型,即将“HttpEvent”替换为“HttpResponse”。请参阅下面的示例。希望能解决它。

enroll(enrollment: IEnrollmentModel, appointment: IAppointmentModel): Observable<HttpResponse<IEnrollmentModel>> {
    const url = `${environment.api.url}enrollment?link=${appointment.link}`;
    return this.httpClient.post<IEnrollmentModel>(url, enrollment, {observe: 'response'});
  }
于 2020-01-03T15:16:04.223 回答
0

因此,由于我在编辑中描述的发现,我能够找到我的错误。不幸的是,错误在于我没有提供任何代码。它位于拦截器中,检查是否缺少身份验证。

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private authenticationService: AuthenticationService) {
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(catchError(err => {
      if (err.status === 401) {
        // auto logout if 401 response returned from api
        this.authenticationService.logout();
        location.reload();
      }

      // const error = err.error.message || err.statusText;     <----- This Line
      // return throwError(err);

      return throwError(err);
    }));
  }
}

收到 aErrorResponse后,拦截器会检查状态401以重定向到登录页面。请注意 return 语句之前的注释行。在这里,错误被解析和缩小,这实际上不是我想要的。知道了这一点,我可以将原始错误传递给throwError函数,我将在我的组件中得到预期的结果。

由于问题响应的想法。

于 2020-01-04T13:40:17.640 回答