onError
関数またはそのドキュメントにバグがあるようです。 この問題は#698ですでに言及されていますが、解決を期待して少し具体化すると思いました。
apollo-boost
またはapollo-link-error
から直接onError
を使用してエラーをインターセプトする場合、ドキュメントには、エラーオブジェクトにresponse
オブジェクトが含まれていると記載されています。エラーを無視します。
これは意図された動作である可能性があるため、ドキュメントのチェックボックスをオンにしましたが、ドキュメントではnetworkError
セクションのサブ段落でresponse
オブジェクトについて言及しているため、それがケース。
予想される行動
response.errors = null;
を設定すると、別のエラーをスローせずにエラーが伝播するのを防ぐことができます。
実際の動作
networkError
をキャッチすると、 response
フィールドが未定義になり、 response.errors
を設定しようとすると構文エラーが発生します。 現時点では私を超えている理由により、これは実際にはネットワークエラーの伝播を防ぎますが、代わりに別のエラーをスローします。
私のセットアップ(MacOS 10.14.1w。Chrome70.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
}
})
});
発行ラベル
このバグの一時的な回避策はありますか?
サーバー環境でapolloクライアントを使用している場合(リゾルバー用に別のGraphQLサーバーからデータを読み取る場合)、デバッグのかなり大きな問題を+1します。
+1
エラーを条件付きで無視するための回避策はありますか?
私もこの問題を抱えています。
私にとっての大きな問題は、これによりUIがこのエラーを認識できなくなることです。 実際に大きなエラーが発生してもロード状態のままです。
私はこれを調べましたが、ドキュメントによると、コールバックに応答する必要があります。
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チームは新しいクライアントとreactバージョンのリリースに集中します。
この問題に関する進展はありますか?
また、これについて何か進展があるのだろうか? または、当面の回避策はありますか? APIからUIにカスタムエラーメッセージを伝播する方法が欲しいのですが。
私も同じ問題に直面していました。 私にとっての回避策は、空のObservableを返すことでした。
サーバーが503に応答した場合に備えて、例外をスローせずに、maintanaceページに静かにリダイレクトしたかっただけです。 これが私のコードです、多分それは誰かを助けるでしょう:
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実際には私のせいでした。AWSAPIゲートウェイを使用して、 200
コード以外のCORS応答を適切に構成しませんでした
問題が発生した場合は、デフォルトの4xxでAPIゲートウェイの応答を追加できます。
または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'
私は同じ障害にぶつかっていて、エラーメッセージを作成するためにメッセージをreactアプリケーションに転送することができないと信じています。 この問題の修正に進展はありますか?
この応答フィールドについては@strassdunnoですが、エラーを処理するためにネットワークエラーをオンに切り替えることができます
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
}
}
})
空のObservableを返す@luki215の回避策を試しましたが、私の場合は、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
に変換します。 理由は、GraphQL規則に従わず、400ステータスコードで{"message": "{ \"key\": \"not valid\"}"}
のような形状を返すRESTエンドポイントを使用しているためです。 これはNetworkErrorとして扱われるべきではありません。
動作:このソリューションは、 mutate
promise 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。
私は解決策を見つけたかもしれないと思います(少なくとも私のエラー伝播の問題に対する):
errorLinkでmap
をforEach
に置き換えると、エラーがUIにエラーを伝播する可能性があります(以前はUIコンポーネントのresult.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に応答した場合に備えて、例外をスローせずに、maintanaceページに静かにリダイレクトしたかっただけです。 これが私のコードです、多分それは誰かを助けるでしょう:
import { Observable } from 'apollo-link'; ... onError(({ networkError }: any) => { if (networkError && networkError.status === 503) { this.redirectService.goToMaintenance(); return Observable.of(); } }); ...
これは私にとってはうまくいきましたが、ドキュメントに記載されていることとは正反対のことをしています。つまり、「エラーコールバックは、リクエストを再試行したい場合、オプションでforward(operation)の呼び出しからオブザーバブルを返すことができます。他に何も返さないはずです。」
今日Apolloを更新した後、上記の私のソリューションは、UIへのapolloフックを介してgraphQLエラーを伝達しなくなりました。
誰かが別の解決策を持っていますか?
@strassは、上記のソリューションで問題が解決する理由を説明できます。 IMOは、 forEach
とmap
を使用してまったく同じことを行います。
もうありません(https://github.com/apollographql/apollo-link/issues/855#issuecomment-538010335を参照)
これについて何か進展はありますか?
応答オブジェクトをまったく取得できない場合に、サーバーが再認証のために「Location」ヘッダーを持つ302を返す場合にどのように対処するのでしょうか。
誰かが何か手がかりを持っているなら、私たちがアポロを落とすことを考えているcosを私に知らせてください:(
これは、 https: //github.com/apollographql/apollo-link/issues/297#issuecomment -350488527に大いに役立ち、ネットワーク応答を読み取ることができます。
認証レイヤー/ゲートウェイAPIから不正な応答が返される場合に重要なこと。
これをコア機能の一部として見たいです!
これについて何か進展はありますか? これが意図された動作である方法はありません。 他に、200以外のステータスコードでGraphQLエラーをクライアントに転送するにはどうすればよいですか?
ネットワークエラーのキャッチと変更で問題が発生した場合は、他の人に注意してください。 私はネットワークエラーを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,
]);
基本的に、一般的なネットワークエラーメッセージであるメッセージを最初の内部エラーメッセージに置き換えます。 ここにたどり着いた私のような何人かの人々を助けるかもしれません。
最も参考になるコメント
この問題に関する進展はありますか?