<p>خطأ ارتباط أبولو - كيفية تحديث رمز غير متزامن؟</p>

تم إنشاؤها على ١٥ يونيو ٢٠١٨  ·  31تعليقات  ·  مصدر: apollographql/apollo-link

تسميات العدد

  • [] وقد التكاثر
  • [ ] خاصية
  • [x] مستندات
  • [] blocking <----- آسف ، ليس الحظر
  • [] مشكلة أولى جيدة

سؤال

السيناريو الدقيق الذي أحاول تحقيقه مذكور هنا:

https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-error#retrying -failed-request

            operation.setContext({
              headers: {
                ...oldHeaders,
                authorization: getNewToken(),
              },
            });

ومع ذلك ، إذا انتهت صلاحية الرمز المميز ، فيجب استدعاء resfreshToken غير المتزامن و "الانتظار" ، قبل أن يتمكن getNewToken إرجاع رمز مصادقة صالح. أعتقد.

سؤالي هو ، كيف أقوم بإجراء مكالمة غير متزامنة resfreshToken . لقد جربت await refreshToken() (الذي يحسم الوعد عند اكتماله) ، ولكن من تتبعات المكدس التي تم تسجيلها ، يبدو أن هذا يعبث كثيرًا مع RxJS. أنا RxJS n00b ، أي مساعدة موضع تقدير كبير!

blocking docs

التعليق الأكثر فائدة

يبدو onError الاستدعاء لا تقبل aync ظيفة أو Promise العوائد. انظر الكود https://github.com/apollographql/apollo-link/blob/59abe7064004b600c848ee7c7e4a97acf5d230c2/packages/apollo-link-error/src/index.ts#L60 -L74

تم الإبلاغ عن هذه المشكلة من قبل: # 190

أعتقد أنه سيكون من الأفضل أن يتعامل apollo-link-error مع Promise ، على غرار ما يفعله apollo-link-retry هنا: # 436

ال 31 كومينتر

إذا كنت أكثر دراية بالوعود ، يمكنك استخدام المساعد fromPromise

import { fromPromise } from 'apollo-link';

return fromPromise(refreshToken().then(token => {
  operation.setContext({
    headers: {
      ...oldHeaders,
      authorization: token,
    },
  });
  return forward(operation);
}))

thymikee جرب الحل الخاص بك وفشل بالرسالة التالية:

Uncaught (in promise) Error: Network error: Error writing result to store for query:
 query UserProfile($id: ID!) {
  UserProfile(id: $id) {
    id
    email
    first_name
    last_name
    activated
    created_at
    updated_at
    last_active
    roles {
      id
      name
      __typename
    }
    permissions {
      name
      value
      __typename
    }
    profile {
      address
      secondary_email
      phone {
        id
        number
        type {
          id
          name
          __typename
        }
        __typename
      }
      __typename
    }
    __typename
  }
}
Cannot read property 'UserProfile' of undefined
    at new ApolloError (ApolloError.js:43)
    at QueryManager.js:327
    at QueryManager.js:759
    at Array.forEach (<anonymous>)
    at QueryManager.js:758
    at Map.forEach (<anonymous>)
    at QueryManager.webpackJsonp../node_modules/apollo-client/core/QueryManager.js.QueryManager.broadcastQueries (QueryManager.js:751)
    at QueryManager.js:254

يظهر الفحص الإضافي أن رابط Apollo onError يتم استدعاؤه مرتين عند استخدام الكود أعلاه. حتى تقييد وعد refresh token ليتم تشغيله مرة واحدة ، لا يصلح الخطأ.

ما يحدث هو:

1) يتم تنفيذ الاستعلام الأولي
2) فشل وتشغيل رابط أبولو onError
3) ؟؟ يتم تشغيل رابط أبولو onError مرة أخرى
4) الوعد بتحديث الرمز المميز ، في onError ينتهي التنفيذ ويتم حله.
5) (لا يتم تنفيذ الاستعلام الأولي مرة ثانية بعد نجاح الوعد)
6) يؤدي الاستعلام الأولي إلى إرجاع نتيجة تحتوي على data أنها غير محددة

إليك الأمل في أن يجد شخص ما حلاً لذلك ، وإلا فسيتعين علينا العودة إلى استخدام رموز الوصول طويلة الأمد بدلاً من تحديثها عند انتهاء الصلاحية.

إذا كان منطق استرداد الرمز المميز الخاص بك صحيحًا ، فيجب استدعاء onError مرة واحدة فقط. يبدو أنك تواجه مشكلات في الاستعلام عن الرمز المميز

thymikee تم تبديل الطلب غير المتزامن بوعد وهمي. لا يزال يفشل مع الرسالة أعلاه ولا يتم تشغيل الاستعلام الأولي مرتين. جميع الرموز صالحة في وقت الاختبار.

رمز:

return fromPromise(
    new Promise((resolve) => {
        let headers = {
            //readd old headers
            ...operation.getContext().headers,
            //switch out old access token for new one
            authorization: `Bearer  mynewaccesstoken`,
        };
        operation.setContext({
            headers
        });
        return resolve(forward(operation));
    })
)

تحرير: تمت إزالة fromPromise وهو يعمل بشكل صحيح. بطريقة ما ، تنتهي معالجة مكدس الارتباط قبل إرجاع النتيجة ، لذلك لا يتم تنفيذ forward(operation) .

بعد تحليل الكود fromPromise والتنفيذ # 172 ، لا يمكن استخدام fromPromise إلا في التخمين مع كائن Apollo Link.

عند البحث عن حل ، عثرت أخيرًا على هذا المشروع: apollo-link-token-Refresh

مكدس رابط أبولو الخاص بي الآن على النحو التالي:

[
   refreshTokenLink,
   requestLink,
   batchHttpLink
]

يتم استدعاء refreshTokenLink دائمًا للتحقق من رمز الوصول قبل تنفيذ أي استجابة لنقطة نهاية الرسم البياني ويعمل مثل السحر.

لسوء الحظ ، يفترض هذا أنه يجب دائمًا مصادقة استدعاء نقطة نهاية الرسم البياني (وهو ، في حالتي).

يبدو onError الاستدعاء لا تقبل aync ظيفة أو Promise العوائد. انظر الكود https://github.com/apollographql/apollo-link/blob/59abe7064004b600c848ee7c7e4a97acf5d230c2/packages/apollo-link-error/src/index.ts#L60 -L74

تم الإبلاغ عن هذه المشكلة من قبل: # 190

أعتقد أنه سيكون من الأفضل أن يتعامل apollo-link-error مع Promise ، على غرار ما يفعله apollo-link-retry هنا: # 436

تواجه نفس المشكلة ، باستخدام apollo مع رد فعل أصلي ، أحتاج إلى إزالة بعض الرموز من AsyncStorage عند الخطأ ، لذا يجب أن تكون وظيفة غير متزامنة

نجح هذا الحل بالنسبة لي: https://stackoverflow.com/a/51321068/60223

لقد قمت بحل هذا عن طريق إنشاء أداة مساعدة promiseToObservable.js :

import { Observable } from 'apollo-link';

export default promise =>
  new Observable((subscriber) => {
    promise.then(
      (value) => {
        if (subscriber.closed) return;
        subscriber.next(value);
        subscriber.complete();
      },
      err => subscriber.error(err)
    );
    return subscriber; // this line can removed, as per next comment
  });

وثم

import { onError } from 'apollo-link-error';
import promiseToObservable from './promiseToObservable';

export default (refreshToken: Function) =>
  onError(({
    forward,
    graphQLErrors,
    networkError = {},
    operation,
    // response,
  }) => {
    if (networkError.message === 'UNAUTHORIZED') { // or whatever you want to check
      // note: await refreshToken, then call its link middleware again!
      return promiseToObservable(refreshToken()).flatMap(() => forward(operation));
    }
  });

@ crazy4groovy شكرًا على subscriber قيمة إرجاع غير صالحة وفقًا للكتابة Observable : بدلاً من ذلك يجب أن تكون ZenObservable.SubscriptionObserver :

export declare type Subscriber<T> = ZenObservable.Subscriber<T>;

export declare const Observable: {
    new <T>(subscriber: Subscriber<T>): Observable<T>;
};

export declare namespace ZenObservable {
    interface SubscriptionObserver<T> {
        closed: boolean;
        next(value: T): void;
        error(errorValue: any): void;
        complete(): void;
    }

    type Subscriber<T> = (observer: SubscriptionObserver<T>) => void | (() => void) | Subscription;
}

على سبيل المثال ، من الآمن إرجاع غير محدد بدلاً من ذلك. أعتقد أنه يجب ذكره في ملف README الخاص بالمشروع.

محدث: لقد أضفت علاقات عامة حول هذا: https://github.com/apollographql/apollo-link/pull/825

تحتل هذه المشكلة مرتبة عالية على Google ، لذا فأنا أشارك الحل هنا لمساعدة بعض الأشخاص: https://gist.github.com/alfonmga/9602085094651c03cd2e270da9b2e3f7

لقد جربت الحل الخاص بك ولكني أواجه مشكلة جديدة:

Argument of type '(this: Observable<{}>, observer: Subscriber<{}>) => Observable<{}> | Promise<{}>' is not assignable to parameter of type '(this: Observable<{}>, subscriber: Subscriber<{}>) => TeardownLogic'.
  Type 'Observable<{}> | Promise<{}>' is not assignable to type 'TeardownLogic'.
    Type 'Observable<{}>' is not assignable to type 'TeardownLogic'.
      Property 'unsubscribe' is missing in type 'Observable<{}>' but required in type 'Unsubscribable'

كيف حالك يا رفاق تخزين رمز المصادقة الجديد بمجرد تحديثه؟

بالتأكيد ، يمكنني تعيين رؤوس جديدة في طلب إعادة المحاولة ، ولكن لا يتم تحديث رمز الوصول الأصلي (الذي أقوم بتخزينه في ملفات تعريف الارتباط) مما يعني أن كل طلب فردي للخادم سيستخدم رمز الوصول القديم (وبالتالي سوف تحتاج إلى التحديث مرة أخرى).

لسبب ما ، أتلقى رسالة الخطأ التالية عندما أحاول تحديث ملفات تعريف الارتباط أثناء التحديث (لقد أنشأت مشكلة جديدة هنا حول هذا الموضوع):

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:470:11)
    at setCookie (/root/SimplyTidyAdmin/node_modules/nookies/dist/index.js:98:17)
    at /root/SimplyTidyAdmin/.next/server/static/CAhshxrRWHVF6Gzbce~pU/pages/_app.js:1273:63
    at process._tickCallback (internal/process/next_tick.js:68:7)

StupidSexyJake ربما https://stackoverflow.com/questions/55356736/change-apollo-client-options-for-jwt-token لقد واجهت مشكلة مماثلة حول كيفية تحديث الرمز المميز

مرحبًا ، شكرًا @ crazy4groovy. لقد جربت الحل الخاص بك ولكن ما زلت أواجه المشكلة ، حيث يتم استدعاء البرنامج الوسيط حيث أقوم بإلحاق الرمز المميز بطلب الرسم البياني قبل تعيين الرمز المميز الجديد على الطلب. وبالتالي ، لا يزال العنوان يحتوي على رمز مميز غير صالح.

معلومات أساسية قليلة: نحصل على خطأ في الشبكة ، عندما يكون الرمز المميز غير صالح ، ومن خلال رمز التحديث ، يمكننا الحصول على رمز جديد وإعادة المحاولة. ولكن نظرًا لاستدعاء البرمجيات الوسيطة قبل جمع رمز التحديث وتعيينه على التخزين المحلي ، فإنه لا يزال يحتوي على الرمز غير الصحيح. يعمل منطق التحديث المميز بشكل جيد ، نظرًا لأننا نحصل بعد ذلك على الرمز المميز الجديد الذي تم تعيينه في النهاية. لقد تم تصحيح المشكلة قليلاً والتوقيت كالتالي:

  • البرامج الوسيطة: تم إرفاق رمز غير صالح
  • تم تقديم طلب للاستعلام
  • خطأ في الشبكة: تم اكتشاف 401 ، لأن الرمز المميز غير صالح ، وفي onError يتم التعامل معه عبر منطق promiseToObservable وإعادة المحاولة.
  • حتى ننتهي من الحصول على الرمز المميز في الوعد onRefreshToken ، فإن البرنامج الوسيط قيد التشغيل الثاني بالفعل مع الرمز القديم.
  • يتم تحديث الرمز المميز في التخزين المحلي ...

إليك مقتطف من هذه الأجزاء (تخطي onRefreshtoken. إنها وظيفة غير متزامنة ، إرجاع الوعد):

  const promiseToObservable = (promise: Promise<any>) =>
    new Observable((subscriber: any) => {
      promise.then(
        value => {
          console.log(subscriber);
          if (subscriber.closed) return;
          subscriber.next(value);
          subscriber.complete();
        },
        err => subscriber.error(err)
      );
    });
  const authMiddleware = setContext((operation: GraphQLRequest) => {
    const token = localStorage.getItem('ca_token');
    return {
      headers: {
        ...(token && !isSkipHeader(operation)
          ? { authorization: `Bearer ${token}` }
          : {})
      }
    };
  });
const errorLink = onError(
    ({
      networkError,
      graphQLErrors,
      operation,
      forward
    }: ErrorResponse): any => {
      if (networkError) {
        switch (networkError.statusCode) {
          case 401:
            console.warn('Refreshing token and trying again');
            // await refreshToken, then call its link middleware again
            return promiseToObservable(onRefreshToken(client.mutate)).flatMap(() => forward(operation));
          default:
            // Handle all other errors here. Irrelevant here.
        }
      }
      if (graphQLErrors) {
         // Handle gql errors, irrelevant here.
      }
    }
  );

هل يمكنك أن تخبرني بما أفتقده هنا؟ شكرا جزيلا مقدما...

حسنًا ، آسف للارتباك ، إن وجد ...

لقد وجدت الإجابة وهي غبية بعد البحث عنها لساعات ووجدت - بالطبع - بعد النشر هنا: أثناء تهيئة عميل Apollo ، قمت بتبديل رابط البرنامج الوسيط والخطأ. الآن يعمل. يجب ان يكون رابط الخطا اولا واضحا ..
قديم: link: from([authMiddleware, errorLink, /* others */])
الجديد: link: from([errorLink, authMiddleware, /* others */])

اسف مجددا..

مرحبا يا شباب،

لدي المشكلة التالية باستخدام onError للتحديث الرموز المميزة. لغرض SSR باستخدام nextjs ، أقوم بجمع البيانات من جميع استعلامات الرسم البياني ، ولكن ماذا يحدث عندما يكون لدينا استعلامان على سبيل المثال وينتهي كل منهما بخطأ بسبب انتهاء صلاحية رمز jwt. ثم يتم تشغيله مرتين خطأ onError ونحن ندعو مرتين للحصول على رموز التحديث باهظة الثمن. لا يمكنني معرفة مصدر المشكلة. هذا هو الكود الذي أستخدمه. هل يمكنك المساعدة في هذا من فضلك.

https://gist.github.com/shaxaaa/15817f1bcc7b479f3c541383d2e83650

لقد تصارعت مع هذه المشكلة قليلاً ، لكنني نجحت أخيرًا في حلها. رميت حزمة معا.

https://github.com/baleeds/apollo-link-refresh-token

يتمثل الاختلاف الأساسي بين هذه الحزمة والحزمة التي تسمى apollo-link-token-Refresh في أن هذه الحزمة ستنتظر حدوث خطأ في الشبكة قبل محاولة التحديث.

اسمحوا لي أن أعرف إذا كان لديكم يا رفاق أفكار للتغيير.

إليك الاستخدام الأساسي:

const refreshTokenLink = getRefreshTokenLink({
  authorizationHeaderKey: 'Authorization',
  fetchNewAccessToken,
  getAccessToken: () => localStorage.getItem('access_token'),
  getRefreshToken: () => localStorage.getItem('refresh_token'),
  isAccessTokenValid: accessToken => isTokenValid(accessToken),
  isUnauthenticatedError: graphQLError => {
    const { extensions } = graphQLError;
    if (
      extensions &&
      extensions.code &&
      extensions.code === 'UNAUTHENTICATED'
    ) {
      return true;
    }
    return false;
  },
});

لقد قمت بحل هذا عن طريق إنشاء أداة مساعدة promiseToObservable.js :

import { Observable } from 'apollo-link';

export default promise =>
  new Observable((subscriber) => {
    promise.then(
      (value) => {
        if (subscriber.closed) return;
        subscriber.next(value);
        subscriber.complete();
      },
      err => subscriber.error(err)
    );
    return subscriber; // this line can removed, as per next comment
  });

وثم

import { onError } from 'apollo-link-error';
import promiseToObservable from './promiseToObservable';

export default (refreshToken: Function) =>
  onError(({
    forward,
    graphQLErrors,
    networkError = {},
    operation,
    // response,
  }) => {
    if (networkError.message === 'UNAUTHORIZED') { // or whatever you want to check
      // note: await refreshToken, then call its link middleware again!
      return promiseToObservable(refreshToken()).flatMap(() => forward(operation));
    }
  });

أستخدمه ووجدت أنه لا يزال يستخدم رمزًا مميزًا قديمًا بعد طلب رمز التحديث. لذلك ، أحاول على النحو التالي:

return promiseToObservable(refreshToken()).flatMap((value) => {
  operation.setContext(({ headers = {} }) => ({
    headers: {
      // re-add old headers
      // ...headers,
      Authorization: `JWT ${value.token}`
    }
  }));
  return forward(operation)
});

ويعمل.
ومع ذلك ، لا تزال هناك مشكلة تتمثل في أنه إذا قمت بإضافة ...headers (يعني إعادة إضافة الرؤوس القديمة) ، فهناك خطأ ما قبل إرسال طلب إعادة التوجيه:
ERROR Error: Network error: Cannot read property 'length' of null
أعتقد أن التفويض في ... رؤوس قد يتعارض مع التفويض الجديد.

المشكلة أعلاه في Apollo-angular "apollo-angular-link-http": "^1.6.0", وليست في Apollo-client "apollo-link-http": "^1.5.16", بينما خطأ الارتباط هو نفسه "apollo-link-error": "^1.1.12",

صيغة أخرى: العيون:

import Vue from 'vue'
import { Observable } from 'apollo-link'
import { onError } from 'apollo-link-error'

const onGraphqlError = async ({ graphQLErrors = [], observer, operation, forward }) => {
  // here you could call the refresh query in case you receive an expired error
  for (let error of graphQLErrors)
    observer.next(forward(operation)) // this line would retry the operation
}

const onNetworkError = async ({ observer, networkError, operation, forward }) => { }

export const errorHandler = opt => new Observable(async observer => {
  try {
    const payload = { ...opt, observer }
    await Promise.all([onGraphqlError(payload), onNetworkError(payload)])
    if (observer.closed) return
    observer.complete()
  } catch (error) {
    observer.error(error)
  }
})

مرحبا! أنا أستخدم نقل websocket الكامل ، وأحتاج إلى طلب استعلام عن الرمز المميز. لا فكرة عن كيفية القيام بذلك.
أريد أن أقوم بطلب استلام عندما يستجيب الخادم بأن accessToken قد انتهت صلاحيته.

import { onError } from "apollo-link-error";

import gql from 'graphql-tag'

// Client: VUE APOLLO
const q = {
    query: gql`query token { token { accessToken } }`,
    manual: true,
    result({ data, loading }) {
        if (!loading) {
            console.log(data)
        }
    },
}

const link = onError(({ graphQLErrors, networkError, operation, response, forward }) => {

    if (networkError) {


        switch (networkError.message) {
            case 'accessTokenExpired':
                console.log('accessTokenExpired')
                return forward(q) // NOT WORKS, NEED HELP
            case 'unauthorized':
                return console.log('unauthorized')
            default:
                return forward(operation)
        }
    }

    return forward(operation)
})

export default link

nikitamarcius لقد نشرنا الحلول أعلاه ، ألق نظرة على

لا يمكنني تحديث الرمز المميز ، هل يمكن لأي شخص تقديم مثال العمل

@ Ramyapriya24 هنا هو الرمز الذي أستخدمه.

import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
import { setContext } from '@apollo/link-context';
import AuthService from 'services/auth-service' // this is my implementation

const asyncAuthLink = setContext(async () => {
    // this is an async call, it will be done before each request
    const { token } = await AuthService.getCredentials();
    return {
      headers: {
        authorization: token
      },
    };
  },
);

const httpLink = new HttpLink({
  uri: 'http://localhost:4000/graphql',
});

export const apolloClient = new ApolloClient({
  cache: new InMemoryCache(),
  link: asyncAuthLink.concat(httpLink),
});

adrianolsk يمكنك تقديم رمز الخدمة كتب

استيراد خدمة AuthService من "services / auth-service" // هذا هو تطبيقي
const {token} = await AuthService.getCredentials () ،

عندما أحاول استيراد الخدمة تظهر لي أخطاء

هذه هي خدمتي ، لقد قرأت فقط AsyncStorage من رد الفعل الأصلي ، لذا بعد تسجيل الدخول ، قمت بتعيين القيمة هناك وقبل كل طلب ، فقط أحصل على المعلومات وتعيينها في الرأس ، يمكنك فعل الشيء نفسه ، أو باستخدام localStorage إذا كنت على الويب.

أين تقوم بتخزين المعلومات التي تريد استخدامها؟

يمكنك فقط استخدام هذا

//save the token after login or when it refreshes
localStorage.setItem('token', yourToken);

واستخدامه

const asyncAuthLink = setContext(() => {
    // grab token from localStorage
    const token = localStorage.getItem('token');
    return {
      headers: {
        authorization: token
      },
    };
  },
);

adrianolsk شكرًا على الشرح ولكني

يمكن لأي شخص معرفة كيفية استخدام الخدمة في ملف module.ts دون استخدام class و constructor

شكرا

أحاول استخدام fromPromise لتحديث الرمز المميز غير المتزامن.
في الأساس باتباع المربع الثالث من هذا المنشور

لقد نجحت في الحصول على الرموز وتخزينها ، ولكن لم يتم الاتصال بأي من catch أو filter أو flatMap . لست متأكدًا من كيفية تصحيح هذا الخطأ ، لذا ستكون بعض الاقتراحات مفيدة.

if (token && refreshToken) {
  return fromPromise(
    getNewToken(client)
      .then(({ data: { refreshToken } }) => {
        console.log("Promise data: ", refreshToken);
        localStorage.setItem("token", refreshToken.token);
        localStorage.setItem("refreshToken", refreshToken.refreshToken);
        return refreshToken.token;
      })
      .catch((error) => {
        // Handle token refresh errors e.g clear stored tokens, redirect to login, ...
        console.log("Error after setting token: ", error);
        return;
      })
  )
    .filter((value) => {
      console.log("In filter: ", value);
      return Boolean(value);
    })
    .flatMap(() => {
      console.log("In flat map");
      // retry the request, returning the new observable
      return forward(operation);
    });
}

adrianolsk : يبدو أن هذا النهج يعمل دائمًا على تحديث الرمز المميز ، حتى قبل انتهاء صلاحيته ، والذي في حالة بعض خدمات المصادقة (على سبيل المثال جلسة check0 الخاصة بـ Auth0 ) ستنشئ رحلة ذهاب وعودة لخادم Auth0 غير ضرورية لكل طلب GraphQL.

أحاول استخدام fromPromise لتحديث الرمز المميز غير المتزامن.
في الأساس باتباع المربع الثالث من هذا المنشور

لقد نجحت في الحصول على الرموز وتخزينها ، ولكن لم يتم الاتصال بأي من catch أو filter أو flatMap . لست متأكدًا من كيفية تصحيح هذا الخطأ ، لذا ستكون بعض الاقتراحات مفيدة.

if (token && refreshToken) {
  return fromPromise(
    getNewToken(client)
      .then(({ data: { refreshToken } }) => {
        console.log("Promise data: ", refreshToken);
        localStorage.setItem("token", refreshToken.token);
        localStorage.setItem("refreshToken", refreshToken.refreshToken);
        return refreshToken.token;
      })
      .catch((error) => {
        // Handle token refresh errors e.g clear stored tokens, redirect to login, ...
        console.log("Error after setting token: ", error);
        return;
      })
  )
    .filter((value) => {
      console.log("In filter: ", value);
      return Boolean(value);
    })
    .flatMap(() => {
      console.log("In flat map");
      // retry the request, returning the new observable
      return forward(operation);
    });
}

لقد وجدت سبب الخطأ. لم يظهر في الكود أعلاه ، لكنني استخدمت وظيفة map لتعيين كل خطأ ناتج. تسبب هذا في عدم قيام onError بإرجاع أي شيء ولم يتم الاشتراك في عملية تجديد الرمز المميز.

محير للغاية واستغرق الأمر وقتًا طويلاً لمعرفة ذلك. شكرا لمؤلف منشور المدونة لمساعدتي.

ERROR Error: Network error: Cannot read property 'length' of null

@ WilsonLau0755 ، كان لدي نفس المشكلة. تم حلها عن طريق تعيين جميع رؤوس null إلى سلسلة فارغة '' .

لماذا لا يتوفر onError للاستخدام مع عدم التزامن فقط؟

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات