Кажется, есть ошибка либо в функции onError
, либо в ее документации. Эта проблема уже упоминалась в # 698, но я подумал, что немного конкретизирую ее в надежде на решение.
При перехвате ошибки с помощью onError
либо из apollo-boost
, либо напрямую из apollo-link-error
в документации указано , что объект ошибки содержит объект response
, который можно использовать для игнорировать ошибки.
Я отметил флажок docs , так как это может быть предполагаемым поведением, но поскольку в документах упоминается объект response
в подпункте раздела networkError
, вероятно, следует немного уточнить, если это так. дело.
Ожидаемое поведение
Установка response.errors = null;
должна предотвратить распространение ошибки без возникновения другой ошибки.
Фактическое поведение
При перехвате networkError
поле response
не определено, что вызывает синтаксические ошибки при попытке установить response.errors
. По причинам, которые на данный момент мне не известны, это фактически предотвращает распространение сетевой ошибки, но вместо этого выдает другую ошибку.
В моей настройке (MacOS 10.14.1 с Chrome 70.0.3538.77) установка response.errors = null
выдаст Uncaught TypeError: Cannot set property 'errors' of undefined
, а response = { errors: null }
выдаст Uncaught Error: "response" is read-only
.
_простая_ репродукция
Ниже приведена репродукция с использованием apollo-boost
. Та же проблема возникает при прямом использовании apollo-link-error
.
import ApolloClient from 'apollo-boost';
const client = ApolloClient({
uri: '/my_api',
onError: (({ response, networkError }) => {
if (networkError && networkError.statusCode === 401) {
console.log(response); // prints 'undefined'
response.errors = null; // will throw 'undefined' error
response = { errors: null }; // will throw a 'read-only' error
}
})
});
Ярлыки выпуска
Есть ли временное решение этой ошибки?
+1 довольно большая проблема для отладки, если вы используете клиент apollo в серверной среде (чтение данных с другого сервера GraphQL для ваших преобразователей).
+1
Есть ли обходной путь для условного игнорирования ошибок?
У меня также есть эта проблема.
Большая проблема для меня заключается в том, что это не позволяет пользовательскому интерфейсу узнать об этой ошибке. Он остается в состоянии загрузки, когда на самом деле возникает большая ошибка.
Я изучил это, и, согласно документам, ответ должен быть дан на обратный вызов:
https://www.apollographql.com/docs/link/links/error.html#callback
При обычном обратном вызове это происходит: https://github.com/apollographql/apollo-link/blob/master/packages/apollo-link-error/src/index.ts#L46 .
Но с networkError: https://github.com/apollographql/apollo-link/blob/master/packages/apollo-link-error/src/index.ts#L62
есть информация о том, когда он будет объединен? :)
Вероятно, совсем скоро команда Apollo сосредоточится на выпуске нового клиента и реактивной версии.
Есть ли прогресс в этом вопросе?
Мне тоже интересно, есть ли прогресс в этом? Или временное решение? Я хотел бы иметь способ распространять пользовательские сообщения об ошибках из API в пользовательский интерфейс.
Я также столкнулся с той же проблемой. Обходной путь для меня состоял в том, чтобы вернуть пустой Observable.
Я просто хотел тихо перенаправить на страницу обслуживания на случай, если сервер ответит 503 - без исключения. Вот мой код, может кому поможет:
import { Observable } from 'apollo-link';
...
onError(({ networkError }: any) => {
if (networkError && networkError.status === 503) {
this.redirectService.goToMaintenance();
return Observable.of();
}
});
...
@ luki215 у меня нет поля кода ошибки
@Sceat , какие apollo-link
вы используете? Я использую apollo-angular-link-http
, так что может быть разница.
@ luki215 luki215 на самом деле это была моя вина, используя AWS API-шлюз, я неправильно настроил ответ CORS для чего-либо еще, что кодирует 200
для людей, столкнувшихся с проблемой, вы можете добавить ответы шлюза API по умолчанию 4xx:
или в serverless.yml
yml
GatewayDefault4XX:
Type: 'AWS::ApiGateway::GatewayResponse'
Properties:
ResponseParameters:
gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
ResponseType: DEFAULT_4XX
RestApiId:
Ref: 'ApiGatewayRestApi'
Я считаю, что нахожусь в той же точке преткновения и не могу пересылать сообщения в свое реагирующее приложение для создания сообщений об ошибках. Есть ли прогресс в исправлении этой проблемы?
@strass не знает об этом поле ответа, но для обработки ошибок вы можете включить сетевую ошибку
export default onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
for (let { extensions: { code } } of graphQLErrors)
handleTheError(code)
}
if (networkError) {
switch (networkError.statusCode) {
case 500:
//
break
case 429:
//
break
case undefined:
//
break
default:
console.error(networkError)
break
}
}
})
Только что попробовал обходной путь @ luki215 по возврату пустого Observable, но в моем случае это теперь заставит react-apollo генерировать исключение:
Uncaught (in promise) TypeError: Cannot read property 'data' of undefined
at Mutation._this.onMutationCompleted (react-apollo.esm.js:627)
at react-apollo.esm.js:564
Я использую это, чтобы изменить ошибку, возвращаемую компоненту, используя Mutation
const errorLink = onError(({ forward, networkError, operation }) => {
if (networkError) {
const { message: errorMessage } = networkError.result;
switch (networkError.statusCode) {
case 400:
if (errorMessage) {
networkError.message = errorMessage;
}
break;
case 403:
window.location = '/users/login';
break;
default:
break;
}
}
forward(operation);
});
Я думаю, что ключевая вещь, которую люди, возможно, ищут здесь, — это возможность переопределить строку ошибки, возвращаемую в networkError
, и это делается с помощью этого networkError.message = 'Some custom error message.'
Придумал хакерский обходной путь после того, как покопался в apollo-link-rest
и этом пакете. Вместо того, чтобы использовать onError
, я переписал свой собственный (ниже).
Цель: перехватить NetworkError
и условно преобразовать его в GraphQLError
. Причина в том, что я использую конечную точку REST, которая не соответствует соглашению GraphQL и возвращает такие формы, как {"message": "{ \"key\": \"not valid\"}"}
с кодом состояния 400. Это не следует рассматривать как NetworkError.
Что работает: это решение действительно передает фактическое сообщение об ошибке из ответа вниз по цепочке таким образом, что я могу получить и проанализировать его в обещании $ mutate
catch
и изменить состояние дочерней формы .
Что не работает:
observer.next({ data: { ... }, errors: { ... } })
для правильной передачи ошибок, но это не работает (эти данные никуда не уходят, и обещание мутации, похоже, не разрешается).observer.next()
и observer.error()
не имеет ожидаемого поведения после этого . Только вызов ошибки, кажется, вступает в силу.const errorLink = new ApolloLink((operation, forward) => {
return new Observable(observer => {
let sub: ZenObservable.Subscription;
try {
sub = forward!(operation).subscribe({
next: result => {
console.log("A proper result looks like:", result);
observer.next(result)
},
error: networkError => {
try {
const { message } = networkError.result;
const error = new GraphQLError(message);
const apolloError = new ApolloError({
errorMessage: "Some error happened",
graphQLErrors: [error],
networkError: undefined,
});
observer.error(new Error(message));
} catch (_) {
observer.error(networkError)
}
},
complete: () => {
console.log("Calling complete()");
observer.complete();
},
});
} catch (e) {
console.log("ErrorLink had an error of its own")
observer.error(e);
}
return () => {
if (sub) sub.unsubscribe();
};
});
});
Мне кажется, что это должно работать, но функция mutate()
, похоже, не разрешает и не отклоняет - ни then()
, ни catch()
не вызываются.
const errorLink = new ApolloLink((operation, forward) => {
return new Observable(observer => {
let sub: ZenObservable.Subscription;
try {
sub = forward!(operation).subscribe({
next: result => {
console.log("A proper result looks like:", result);
observer.next(result)
},
error: networkError => {
try {
const { message } = networkError.result;
const error = new GraphQLError(message);
// this is called, but it seems to be the end of the line
console.log("Intercepting error, returning success");
observer.next({ data: {}, errors: [ error ]});
} catch (localError) {
console.error("Error in link:", localError);
observer.error(networkError)
}
},
complete: () => {
console.log("Calling complete()");
observer.complete();
},
});
} catch (e) {
console.log("ErrorLink had an error of its own")
observer.error(e);
}
return () => {
if (sub) sub.unsubscribe();
};
});
});
Просто нажимаю...
Натыкаюсь на ту же ошибку сейчас.
Хотите сбросить ошибку в поле ответа, чтобы обработать ошибку самого компонента...
Какой-либо прогресс?
+1 по той же проблеме.
Я думаю, что, возможно, нашел решение (по крайней мере, для моей проблемы с распространением ошибок):
Замена map
на forEach
в errorLink означает, что ошибки могут передавать ошибки в пользовательский интерфейс (ранее результат.error в компоненте пользовательского интерфейса был неопределенным, теперь он содержит ошибки):
const link = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
- graphQLErrors.map(({ message, locations, path }) =>
+ graphQLErrors.forEach(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
),
);
if (networkError) console.log(`[Network error]: ${networkError}`);
});
Я также столкнулся с той же проблемой. Обходной путь для меня состоял в том, чтобы вернуть пустой Observable.
Я просто хотел тихо перенаправить на страницу обслуживания на случай, если сервер ответит 503 - без исключения. Вот мой код, может кому поможет:
import { Observable } from 'apollo-link'; ... onError(({ networkError }: any) => { if (networkError && networkError.status === 503) { this.redirectService.goToMaintenance(); return Observable.of(); } }); ...
Это сработало для меня, но делает прямо противоположное тому, что говорится в документации, т. Е. «Обратный вызов ошибки может необязательно возвращать наблюдаемое из вызова переадресации (операции), если он хочет повторить запрос. Он не должен возвращать что-либо еще».
После сегодняшнего обновления Apollo мое вышеприведенное решение больше не переносит ошибки graphQL через хуки apollo в пользовательский интерфейс.
У кого-нибудь есть другое решение?
@strass , можете ли вы объяснить, почему ваше решение, приведенное выше , устраняет проблему. ИМО они делают то же самое, используя forEach
и map
.
Больше нет (см. https://github.com/apollographql/apollo-link/issues/855#issuecomment-538010335)
Есть ли прогресс в этом?
Как мы должны поступать в случае, когда сервер возвращает 302 с заголовком «Местоположение» для повторной аутентификации, если мы вообще не можем получить объект ответа?
Если у кого-то есть какие-либо подсказки, дайте мне знать, потому что мы думаем сбросить Аполлона :(
Это очень помогло мне https://github.com/apollographql/apollo-link/issues/297#issuecomment -350488527 и позволяет читать сетевые ответы.
Что-то, что имеет решающее значение, когда есть несанкционированные ответы, возвращаемые от API-интерфейсов уровней аутентификации/шлюза.
Я хотел бы видеть это как часть основного функционала!
Есть ли прогресс в этом? Это никоим образом не является предполагаемым поведением. Как еще можно пересылать ошибки GraphQL клиенту с кодом состояния, отличным от 200?
Просто примечание для всех, кто сталкивается с проблемой перехвата и изменения сетевых ошибок. Я пытался преобразовать сетевые ошибки во внутреннюю ошибку из graphql, и вот что у меня получилось:
const errorHandler = onError(({ graphQLErrors, networkError, operation, forward, response }) => {
if (graphQLErrors) {
console.error('apollo errors', graphQLErrors);
}
if (networkError) {
console.error('apollo network errors', networkError);
if (!!networkError['error'] && !!networkError['error']['errors'] && networkError['error']['errors'][0]) {
console.error('unwrapping apollo network errors');
networkError.message = networkError['error']['errors'][0].message;
// you may also be able to set networkError.message to null based on criteria to remove the error, even if you can't prevent an error from being triggered altogether
}
}
}
);
// Create an http link:
const httpLink = new HttpLink(this.httpClient).create({
uri: this.uri,
headers: new HttpHeaders({
Authorization: this.token
}),
includeExtensions: true
});
const httpErrorLink = ApolloLink.from([
errorHandler,
httpLink,
]);
По сути, я заменяю сообщение, которое является общим сообщением об ошибке сети, на первое внутреннее сообщение об ошибке. Может помочь некоторым людям вроде меня, которые оказались здесь.
Самый полезный комментарий
Есть ли прогресс в этом вопросе?