#angular #rxjs
#angular #rxjs
Вопрос:
У меня есть приложение Angular, которое использует GraphQL в качестве структуры API. Когда в серверной части выдается ошибка, запрос имеет статус 500, но все равно возвращает стандартный JSON (может содержать массив «errors»). Однако этот статус 500 вызывает ошибку в наблюдаемом, когда я только подписываюсь на него. Я хочу проигнорировать выданную ошибку и вместо этого просто проверить наличие массива ошибок в ответе. Мой первый подход:
login(email: string, password: string) {
this.loginGQL.watch({email, password}).valueChanges.subscribe(result => {
if(!result.errors || result.errors.length === 0) {
this.authData.next(result.data.login);
} else {
this.error.next(result.errors[0].message);
}
});
}
Я попробовал этот подход, чтобы попытаться решить проблему:
login(email: string, password: string) {
this.loginGQL.fetch({email, password}).pipe(map(result =>
result.data
), catchError(
err => {
console.log(err);
return err.message;
}
)).subscribe(
(finalResult: string | AuthData) => {
if(typeof finalResult !== "string") {
this.authData.next(finalResult);
} else {
console.log(finalResult);
this.error.next(finalResult);
}
}
);
}
Однако это не только отбрасывает ответ, но и сообщение об ошибке также каким-то образом разбивается на отдельные буквы. Не лучший опыт.
Каков был бы наилучший подход к этому? Заранее спасибо.
Ответ №1:
Вы правы в использовании catchError
оператора, но одним из его требований является то, что он должен возвращать наблюдаемое. И поскольку вы возвращаетесь err.message
, каждый символ строки выдается по отдельности. Вместо этого вы могли бы использовать of()
функцию RxJS для возврата ошибки в виде next
уведомления. Она будет отправлена на next
обратный вызов подписки. Попробуйте следующее
import { of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
login(email: string, password: string) {
this.loginGQL.fetch({ email, password }).pipe(
map(result => result.data),
catchError(err => {
console.log(err);
return of(err); // <-- you could also return the required array here
})
).subscribe(
(finalResult: string | AuthData) => {
if (typeof finalResult !== "string") {
this.authData.next(finalResult);
} else {
console.log(finalResult);
this.error.next(finalResult);
}
}
);
}
Комментарии:
1. Это решение не только кажется наиболее ортодоксальным в соответствии с лучшими практиками (я слышал о функции ‘of’ раньше, когда я проходил курс Angular, я так и не узнал, что именно она делает), но оно также работает почти без сбоев. Единственное изменение, которое я внес в код, это: « возврат (err.NetworkError.error.errors[0].message); « Это возвращает исходное сообщение с сервера вместо сообщения об ошибке, сгенерированного во внешнем интерфейсе. Спасибо!
Ответ №2:
Observable.subscribe()
имеет пару перегрузок, которые обрабатывают сценарии ошибок. subscribe
Метод принимает до 3 аргументов ( next
, error
, complete
). Мы можем использовать второй error
аргумент для обработки, перехватывать исключение и обрабатывать его так, как мы хотим. Подробная информация
login(email: string, password: string) {
this.loginGQL.watch({email, password}).valueChanges.subscribe(result => {
this.authData.next(result.data.login);
}, errorResult => {
if(errorResult.errors amp;amp; errorResult.errors.length > 0) {
this.error.next(errorResult.errors[0].message);
}
});
}
Обратите внимание, что я удалил if(!result.errors || result.errors.length === 0)
условие из next
аргумента функции. Если вызвана функция next
или complete
, то ошибка не была выдана. Я оставил обратное условию в error
функции, поскольку я предпочитаю иметь «проверки работоспособности» в коде, чтобы предотвратить случайные ошибки нулевой ссылки.
Комментарии:
1. Как это решает его проблему?
2. Я в замешательстве. Как я понял, первоначальный вопрос заключается в том, что 500 вызывает ошибку при подписке, и они хотят знать, как игнорировать ошибку и проверять только массив ошибок в ответе. Этот ответ использует
error
аргумент для обработки любых ошибок из наблюдаемого и проверяет, используя обратную логику из первоначальной попытки.
Ответ №3:
Я думаю, вы могли бы попробовать что-то вроде этого:
src$.pipe(
catchError(err => {
// throwing another error so that `retryWhen` will intercept it
const sources = [throwError(err)];
// send the `errors` array as a `next` notification
err.status === 500 amp;amp; sources.unshift(of(err.errors))
return concat(...sources);
}),
// make sure the subscription is keept alive after `500` errors
retryWhen(errors => errors.pipe(filter(err => err.status === 500))),
)