#angular #typescript #observable
Вопрос:
мне нужно поймать тело ответа, созданное моим REST API, которое выдает ошибку http 406 с пользовательским телом ответа, но в моем angular я могу поймать только статус заголовка «Неприемлемо», я не могу получить тело, как я могу получить тело вместо строки «Неприемлемо»? и я тоже получил эту ошибку TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
, которая заключается в том, что я не знаю, какая часть вызывает эту ошибку. Вот как я это делаю :
сначала я создаю глобальный класс обслуживания, который выглядит следующим образом :
constructor(
private http: HttpClient,
private alertx: AlertService) { }
post<T>(url: string, body?: any, header?: HttpHeaders, param?: HttpParams): Observable<HttpResponse<T>>{
return this.http.post<T>(url, body,
{headers : header ? header : this.headers,
observe: 'response',
responseType: 'json',
params: param})
.pipe(catchError(err => {
const error = err.error?.error_description || err.error?.message || err.statusText;
console.log(err);
console.log('here i am');
return throwError(error);
}))
.pipe(timeout(10000), catchError(err => {
if (err instanceof TimeoutError) {
this.alertx.error('Timeout Exception');
return throwError('Timeout Exception');
}
}))
.pipe(shareReplay());
}
я попытался утешить его.зарегистрируйте ошибку, в ней просто появляется строка «Неприемлемо», и она продолжается с помощью console.log («вот я»); она распечатана правильно, и я не могу найти причину TypeError
вот как я использую функцию выше :
requestCancel(data: SelectItem, reasonCancel: string): Observable<any> {
const request: RequestResponse<SelectItem> = new RequestResponse<SelectItem>(data);
request.message = reasonCancel;
return this.rest.post<any>(`${environment.apiUrl}${endpoint.sales_order.request_cancel}`, request).pipe(map(
response => {
return response.body.data;
}));
}
когда я пытаюсь утешить.зарегистрируйте ответ, он не появился. Я думаю, что моя функция перестает работать в моей функции post в моем глобальном классе обслуживания, что я сделал не так?
—————— ОБНОВЛЕНИЕ МОЕГО КОДА ———————
я создаю класс HttpRequestInterceptor для обработки ошибки, вот мой класс :
@Injectable()
export class HttpRequestInterceptor implements HttpInterceptor {
user: UserModel;
prevUrl: string = '';
constructor(
private loginSvc: LoginService,
private alertx: AlertService,
private sharedService: SharedService) {
this.sharedService.currentUserSubject.subscribe(user => this.user = user);
}
intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.sharedService.setLoading(true, httpRequest.url);
return next.handle(httpRequest).pipe(catchError(err => {
if ([401, 403].includes(err.status) /* amp;amp; this.user */) {
// auto logout if 401 or 403 response returned from api
this.sharedService.setLoading(false, httpRequest.url);
this.loginSvc.removeLocal();
}
this.sharedService.setLoading(false, httpRequest.url);
const error = err.statusText || err.statusText ' ' err.error?.message || err.statusText ' ' err.error?.error_description;
this.alertx.error(error, {autoClose: true});
return throwError(err.error?.message);
}))
.pipe(map<HttpEvent<any>, any>((evt: HttpEvent<any>) => {
if (evt instanceof HttpResponse) {
this.sharedService.setLoading(false, httpRequest.url);
}
return evt;
}));
}
}
when i console.log my err.error?.message
i can catch the error properly, then i the value passed to here :
post<T>(url: string, body?: any, header?: HttpHeaders, param?: HttpParams): Observable<HttpResponse<T>>{
return this.http.post<T>(url, body,
{headers : header ? header : this.headers,
observe: 'response',
responseType: 'json',
params: param})
.pipe(catchError(err => {
console.log(err);
return throwError(err);
}))
.pipe(timeout(10000), catchError(err => {
if (err instanceof TimeoutError) {
this.alertx.error('Timeout Exception');
return throwError('Timeout Exception');
}
}))
.pipe(shareReplay());
}
до тех пор, пока я все еще могу правильно поймать ошибку, когда я console.log(err)
, но когда я использую post
функцию, я не могу поймать ошибку, и я получил ошибку в консоли браузера. Вот моя функция :
requestCancel(data: SelectItem, reasonCancel: string): Observable<any> {
const request: RequestResponse<SelectItem> = new RequestResponse<SelectItem>(data);
request.message = reasonCancel;
return this.rest.post<any>(`${environment.apiUrl}${endpoint.sales_order.request_cancel}`, request).pipe(map(
response => {
return response.body.data;
}))
.pipe(catchError(err => {
// i cannot get anything here
console.log(err);
return err;
}));
}
я не могу зарегистрировать свою ошибку, она ничего не печатает, я думаю, что моя функция разбилась и вместо этого выдает эту ошибку :
TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
что я все еще пропустил здесь?
Ответ №1:
Вы можете написать перехватчик для обработки ошибок в 1 месте. Это было бы удобнее, потому что вам не придется обрабатывать имитационные сценарии в разных службах
@Injectable({
providedIn: 'root',
})
export class RequestInterceptor implements HttpInterceptor {
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
tap( // or catchError operator
(event: HttpEvent<any>) => event,
(error: any) => {
if (error instanceof HttpErrorResponse) {
if (error.status === 406) {
// do something here
}
}
}
)
);
}
}
И добавьте RequestInterceptor в массив поставщиков AppModule
@NgModule({
imports: [
...
],
declarations: [
...
],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: RequestInterceptor, multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule {}
Комментарии:
1. я попробовал ваш ответ, но все еще не могу правильно уловить ошибку
2. Вы добавили RequestInterceptor в массив поставщиков AppModule? См. Обновленный ответ
3. Я попробовал ваш ответ, но это ошибка «ошибиться», это сообщение об ошибке что-то вроде «Произошла неожиданная ошибка сервера». Но я хочу получить реальное сообщение об ошибке
Ответ №2:
Как согласовано с ответом Тимоти, HttpInterceptor
удобно обрабатывать ошибки из одного места, что обеспечивает способ перехвата HTTP
запросов и ответов для их преобразования или обработки перед передачей.
Существует два варианта использования, которые могут быть реализованы в перехватчике.
Во-первых, retry
HTTP
вызовите один или несколько раз, прежде чем выдавать ошибку. В некоторых случаях, например, если есть тайм-аут, лучше продолжить, не создавая исключения.
Для этого используйте retry
оператор from RxJS
для повторной подписки на наблюдаемое.
Затем проверьте состояние исключения и посмотрите, не является ли оно 401
несанкционированной ошибкой. Затем проверьте состояние исключения и посмотрите, является ли оно 406
недопустимой ошибкой. При обеспечении безопасности на основе токенов попробуйте обновить токен, если это необходимо. Если это не сработает, перенаправьте пользователя на страницу входа в систему или в другое место.
import { Injectable } from '@angular/core';
import {
HttpEvent, HttpRequest, HttpHandler,
HttpInterceptor, HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
@Injectable()
export class ServerErrorInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
retry(1),
catchError((error: HttpErrorResponse) => {
if (error.status === 401) {
// refresh token
}
else if (error.status === 406) {
// do something here
}
else {
return throwError(error);
}
})
);
}
}
Здесь вы можете retry
один раз, прежде чем проверять состояние ошибки, повторить ошибку. Обновление токенов безопасности зависит от вас, если это необходимо.
Комментарии:
1. я попробовал ваше решение, но я все еще не могу поймать ошибку, когда она возникла, я обновлю свой вопрос