Apollo-link: Bidang respons tidak ditentukan untuk networkError [apollo-link-error]

Dibuat pada 6 Nov 2018  ·  29Komentar  ·  Sumber: apollographql/apollo-link


Tampaknya ada bug dalam fungsi onError atau dokumentasinya. Masalah ini telah disebutkan di #698 tetapi saya pikir saya akan menyempurnakannya sedikit dengan harapan akan ada penyelesaian.

Saat mencegat kesalahan menggunakan onError baik dari apollo-boost atau langsung dari apollo-link-error dokumentasi menyatakan bahwa objek kesalahan berisi objek response , yang dapat digunakan untuk mengabaikan kesalahan.

Saya telah menandai kotak centang dokumen karena ini mungkin perilaku yang dimaksudkan, tetapi karena dokumen menyebutkan objek response dalam sub-paragraf dari bagian networkError , itu mungkin harus diklarifikasi sedikit jika itu kasus.

Perilaku yang Diharapkan
Menyetel response.errors = null; akan mencegah galat menyebar tanpa menimbulkan kesalahan lain.

Perilaku Sebenarnya
Saat menangkap networkError bidang response tidak terdefinisi, menyebabkan kesalahan sintaks saat mencoba mengatur response.errors . Untuk alasan yang berada di luar jangkauan saya saat ini, ini sebenarnya mencegah kesalahan jaringan menyebar, tetapi malah menimbulkan kesalahan lain.

Dalam pengaturan saya (MacOS 10.14.1 w. Chrome 70.0.3538.77) pengaturan response.errors = null akan menghasilkan Uncaught TypeError: Cannot set property 'errors' of undefined dan response = { errors: null } akan menghasilkan Uncaught Error: "response" is read-only .

skaermbillede 2018-11-06 kl 15 08 10

skaermbillede 2018-11-06 kl 15 09 20

Reproduksi _sederhana_

Berikut ini adalah reproduksi menggunakan apollo-boost . Masalah yang sama terjadi menggunakan apollo-link-error secara langsung.

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 
    }
  })
});

Label Masalah

  • [ ] memiliki-reproduksi
  • [ ] fitur
  • [x] dokumen
  • [ ] memblokir
  • [ ] edisi pertama yang bagus

docs

Komentar yang paling membantu

Ada kemajuan dalam masalah ini?

Semua 29 komentar

Apakah ada solusi sementara untuk bug ini?

Memberi +1 masalah yang cukup besar untuk debugging jika Anda menggunakan klien apollo di lingkungan server (membaca data dari server GraphQL yang berbeda untuk resolver Anda).

+1
Apakah ada solusi untuk mengabaikan kesalahan secara kondisional?

Saya juga memiliki masalah ini.

Masalah besar bagi saya adalah ini mencegah UI untuk mengetahui kesalahan ini. Itu tetap pada status pemuatan ketika sebenarnya ada kesalahan besar.

ada wawasan kapan akan digabung? :)

Mungkin dalam waktu dekat, tim apollo akan fokus untuk merilis klien baru dan versi reaksi.

Ada kemajuan dalam masalah ini?

Saya juga bertanya-tanya apakah ada kemajuan dalam hal ini? Atau solusi sementara itu? Saya ingin memiliki cara untuk menyebarkan pesan kesalahan khusus dari API ke UI.

Saya juga menghadapi masalah yang sama. Solusi bagi saya adalah mengembalikan Observable kosong.

Saya hanya ingin secara diam-diam mengarahkan ulang ke halaman maintanace jika server merespons 503 - tanpa membuang pengecualian. Ini kode saya, mungkin itu akan membantu seseorang:

import { Observable } from 'apollo-link';

...

onError(({ networkError }: any) => {
      if (networkError && networkError.status === 503) {
        this.redirectService.goToMaintenance();
        return Observable.of();
      }
});

...

@luki215 saya tidak memiliki bidang kode kesalahan
image

@Sceat apollo-link yang Anda gunakan? Saya menggunakan apollo-angular-link-http , jadi mungkin itu perbedaannya.

@luki215 itu sebenarnya salah saya, menggunakan gateway api AWS saya tidak mengonfigurasi respons CORS dengan benar untuk hal lain yang kode 200

untuk orang-orang yang mengalami masalah, Anda dapat menambahkan respons gateway api di 4xx default:
image

atau di 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'

Saya yakin saya mencapai titik tersandung yang sama dan saya tidak dapat meneruskan pesan ke aplikasi reaksi saya untuk membuat pesan kesalahan. Apakah ada kemajuan dalam perbaikan untuk masalah ini?

@strass tidak tahu tentang bidang respons ini tetapi untuk menangani kesalahan, Anda dapat mengaktifkan kesalahan jaringan

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
        }
    }
})

Baru saja mencoba solusi @luki215 untuk mengembalikan Observable yang kosong tetapi dalam kasus saya yang sekarang akan membuat react-apollo melempar pengecualian:

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

Saya menggunakan ini untuk mengubah kesalahan yang dikembalikan ke komponen menggunakan 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);
});

Saya pikir hal utama yang mungkin dicari orang di sini adalah kemampuan untuk mengganti string kesalahan yang dikembalikan dalam networkError dan selesai dengan networkError.message = 'Some custom error message.' ini

Muncul dengan solusi peretasan setelah menggali apollo-link-rest dan paket ini. Daripada menggunakan onError , saya menulis ulang sendiri (di bawah).

Maksud: mencegat NetworkError dan mengubahnya secara kondisional menjadi GraphQLError . Alasannya, saya menggunakan titik akhir REST yang tidak mengikuti konvensi GraphQL, dan mengembalikan bentuk seperti {"message": "{ \"key\": \"not valid\"}"} dengan kode status 400. Itu tidak boleh diperlakukan sebagai NetworkError.

Apa yang berhasil: solusi ini meneruskan pesan kesalahan aktual dari respons ke bawah rantai, dengan cara yang saya dapat mengambil dan menguraikannya dalam mutate janji catch dan memodifikasi status formulir anak .

Apa yang tidak berfungsi:

  • Saya lebih suka menggunakan observer.next({ data: { ... }, errors: { ... } }) untuk meneruskan kesalahan dengan cara yang benar, tetapi itu tidak berhasil (data itu tidak ke mana-mana, dan janji mutasi tampaknya tidak terselesaikan).
  • memanggil observer.next() dan observer.error() secara berurutan tidak memiliki perilaku yang saya harapkan, mengikuti this . Hanya panggilan kesalahan yang tampaknya berlaku.
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();
      };
    });
  });

Bagi saya sepertinya ini harus berfungsi, tetapi fungsi mutate() tampaknya tidak menyelesaikan atau menolak - then() maupun catch() tidak dipanggil.

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();
      };
    });
  });

Hanya mendorong...
Tersandung pada kesalahan yang sama sekarang.
Ingin mengatur ulang kesalahan di bidang respons untuk menangani kesalahan pada komponen itu sendiri ...

Adakah peningkatan?

+1 pada masalah yang sama.

Saya pikir saya mungkin telah menemukan solusi (setidaknya untuk masalah propagasi kesalahan saya):

Mengganti map dengan forEach di errorLink berarti kesalahan dapat menyebarkan kesalahan ke UI (sebelumnya result.error dalam komponen UI tidak ditentukan, sekarang memiliki kesalahan):

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}`);
});

Saya juga menghadapi masalah yang sama. Solusi bagi saya adalah mengembalikan Observable kosong.

Saya hanya ingin secara diam-diam mengarahkan ulang ke halaman maintanace jika server merespons 503 - tanpa membuang pengecualian. Ini kode saya, mungkin itu akan membantu seseorang:

import { Observable } from 'apollo-link';

...

onError(({ networkError }: any) => {
      if (networkError && networkError.status === 503) {
        this.redirectService.goToMaintenance();
        return Observable.of();
      }
});

...

Ini berhasil untuk saya, tetapi melakukan kebalikan dari apa yang dikatakan dokumentasi, yaitu "Panggilan balik kesalahan dapat secara opsional mengembalikan yang dapat diamati dari panggilan ke depan (operasi) jika ingin mencoba kembali permintaan. Seharusnya tidak mengembalikan apa pun."

Setelah memperbarui Apollo hari ini, solusi saya di atas tidak lagi membawa kesalahan graphQL melalui apollo-kait ke UI.

Apakah ada yang punya solusi lain?

@strass dapatkah Anda menjelaskan mengapa solusi Anda di atas memperbaiki masalah. IMO mereka melakukan hal yang persis sama menggunakan forEach dan map .

Tidak lagi (lihat https://github.com/apollographql/apollo-link/issues/855#issuecomment-538010335 )

Ada kemajuan dalam hal ini?

Bagaimana kita dimaksudkan untuk menangani kasus di mana server mengembalikan 302 dengan header "Location" untuk mengautentikasi ulang, jika kita tidak bisa mendapatkan objek respons sama sekali?

Jika seseorang memiliki petunjuk, beri tahu saya karena kami berpikir untuk menjatuhkan apollo :(

Ini membantu saya secara besar-besaran https://github.com/apollographql/apollo-link/issues/297#issuecomment -350488527 dan memungkinkan respons jaringan untuk dibaca.

Sesuatu yang sangat penting ketika ada tanggapan tidak sah yang dikembalikan dari lapisan otentikasi/API gateway.

Saya ingin melihat ini sebagai bagian dari fungsionalitas inti!

Ada kemajuan dalam hal ini? Tidak mungkin ini adalah perilaku yang dimaksudkan. Bagaimana lagi seseorang dapat meneruskan kesalahan GraphQL ke klien dengan kode status non-200?

Sekedar catatan untuk orang lain yang mengalami masalah dengan menangkap dan memodifikasi kesalahan jaringan. Saya mencoba membuka kesalahan jaringan ke kesalahan dalam dari graphql dan inilah yang saya dapatkan:

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,
]);

Pada dasarnya saya mengganti pesan yang merupakan pesan kesalahan jaringan umum dengan pesan kesalahan internal pertama. Mungkin membantu beberapa orang seperti saya yang berakhir di sini.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat