يبدو أن هناك خطأ في وظيفة onError
أو في وثائقها. تم ذكر المشكلة بالفعل في # 698 لكنني اعتقدت أنني سأقوم بتجسيدها قليلاً على أمل التوصل إلى حل.
عند اعتراض خطأ باستخدام onError
إما من apollo-boost
أو مباشرة من apollo-link-error
، تشير الوثائق إلى أن كائن الخطأ يحتوي على كائن response
، والذي يمكن استخدامه تجاهل الأخطاء.
لقد قمت بتمييز مربع اختيار المستندات نظرًا لأن هذا قد يكون سلوكًا مقصودًا ، ولكن كما تشير المستندات إلى الكائن response
في فقرة فرعية من القسم networkError
، فمن المحتمل أن يتم توضيحه قليلاً إذا كان هذا صحيحًا القضية.
سلوك متوقع
يجب أن يمنع تعيين response.errors = null;
انتشار الخطأ دون حدوث خطأ آخر.
السلوك الفعلي
عند التقاط networkError
، يكون الحقل response
غير محدد ، مما يتسبب في حدوث أخطاء في بناء الجملة عند محاولة تعيين response.errors
. لأسباب خارجة عني في الوقت الحالي ، يمنع هذا في الواقع خطأ الشبكة من الانتشار ، ولكنه يلقي بخطأ آخر بدلاً من ذلك.
في الإعداد الخاص بي (MacOS 10.14.1 w. 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
ولكن مع خطأ الشبكة: https://github.com/apollographql/apollo-link/blob/master/packages/apollo-link-error/src/index.ts#L62
أي فكرة عن موعد دمجها؟ :)
ربما قريبًا جدًا ، يركز فريق أبولو على إصدار العميل الجديد وإصدار رد الفعل.
أي تقدم في هذه المسألة؟
أتساءل أيضًا عما إذا كان هناك أي تقدم في هذا الشأن؟ أو حل بديل في هذه الأثناء؟ أرغب في الحصول على طريقة لنشر رسائل الخطأ المخصصة من واجهة برمجة التطبيقات إلى واجهة المستخدم.
كنت أيضا أواجه نفس المشكلة. كان الحل البديل بالنسبة لي هو إرجاع 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 لقد كان خطأي حقًا ، باستخدام بوابة 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 dunno حول حقل الاستجابة هذا ولكن للتعامل مع الأخطاء ، يمكنك تشغيل خطأ في الشبكة
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 فارغ ولكن في حالتي ، هذا سيجعل رد فعل أبولو يرمي استثناءً:
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. لا ينبغي التعامل مع ذلك على أنه خطأ في الشبكة.
ما ينجح: هذا الحل يقوم بتمرير رسالة الخطأ الفعلية من الاستجابة إلى أسفل السلسلة ، بطريقة يمكنني استردادها وتحليلها ضمن 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 يعني أن الأخطاء يمكن أن تنشر الأخطاء إلى واجهة المستخدم (كان الخطأ الناتج سابقًا في مكون واجهة المستخدم غير محدد ، والآن يحتوي على الخطأ (الأخطاء)):
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 من خلال ربط أبولو بواجهة المستخدم.
هل لدى أي شخص حل آخر؟
strass ، هل يمكنك توضيح سبب إصلاح الحل أعلاه للمشكلة. IMO يفعلون نفس الشيء تمامًا باستخدام forEach
و map
.
لم يعد الأمر كذلك (انظر https://github.com/apollographql/apollo-link/issues/855#issuecomment-538010335)
أي تقدم في هذا؟
كيف يُقصد بنا التعامل مع حالة يقوم فيها الخادم بإرجاع الرقم 302 برأس "الموقع" لإعادة المصادقة ، إذا لم نتمكن من الحصول على كائن الاستجابة على الإطلاق؟
إذا كان لدى شخص ما أي دليل ، فأخبرني لأننا نفكر في إسقاط أبولو :(
ساعدني هذا بشكل كبير https://github.com/apollographql/apollo-link/issues/297#issuecomment -350488527 ويسمح بقراءة استجابات الشبكة.
شيء مهم عندما تكون هناك استجابات غير مصرح بها يتم إرجاعها من طبقات المصادقة / واجهات برمجة تطبيقات البوابة.
أرغب في رؤية هذا كجزء من الوظائف الأساسية!
أي تقدم في هذا؟ لا توجد طريقة هذا هو السلوك المقصود. وإلا كيف يمكن إعادة توجيه أخطاء GraphQL إلى العميل برمز حالة غير 200؟
مجرد ملاحظة لأي شخص آخر يواجه مشكلة في اكتشاف أخطاء الشبكة وتعديلها. كنت أحاول إلغاء تغليف أخطاء الشبكة بالخطأ الداخلي من الرسم البياني وإليك ما انتهى بي الأمر:
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,
]);
في الأساس ، استبدل الرسالة التي تمثل رسالة خطأ عامة في الشبكة بأول رسالة خطأ داخلي. قد يساعد بعض الناس مثلي الذين انتهى بهم المطاف هنا.
التعليق الأكثر فائدة
أي تقدم في هذه المسألة؟