Apollo-link-rest: Arahan `@rest` tidak berfungsi di lingkungan SSR

Dibuat pada 7 Jan 2019  ·  9Komentar  ·  Sumber: apollographql/apollo-link-rest

Hai!

Saya memiliki kueri graphql @rest yang berfungsi sempurna dalam pengembangan/browser, tetapi ketika saya menjalankan kode yang sama di server (SSR), itu gagal dengan pesan kesalahan samar yang panjang.

(jika saya menonaktifkan direktif @rest , semuanya berfungsi dengan sempurna, baik di browser maupun di SSR).

Jejak tumpukan:

(node:26034) UnhandledPromiseRejectionWarning: Error: Network error: current.forEach is not a function
    at new ApolloError (.../demo-component/node_modules/src/errors/ApolloError.ts:56:5)
    at .../demo-component/node_modules/src/core/QueryManager.ts:512:31
    at .../demo-component/node_modules/src/core/QueryManager.ts:1046:11
    at Array.forEach (<anonymous>)
    at .../demo-component/node_modules/src/core/QueryManager.ts:1045:10
    at Map.forEach (<anonymous>)
    at QueryManager.broadcastQueries (.../demo-component/node_modules/src/core/QueryManager.ts:1039:18)
    at .../demo-component/node_modules/src/core/QueryManager.ts:411:18
(node:26034) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 5)
(node:26034) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Tolong saran :/

Komentar yang paling membantu

Menambahkan ini di file bootstrap saya menyelesaikan semua masalah saya: D

if (global.Headers == null) {
    const fetch = require('node-fetch');
    global.Headers = fetch.Headers;
}

perhatikan menggunakan node-fetch alih-alih fetch-headers menyelesaikan masalah!

Semua 9 komentar

Sedikit lebih menggali, saya hanya mencoba menjalankan kueri di NodeJS, tanpa khawatir tentang SSR dll,

dan memiliki kode ini:

            client
                .query({query: Site, variables: {domain: "demo.example.com"}})
                .then(
                    () => console.log("Fullfilled"),
                    ({graphQLErrors, networkError, message, extraInfo}) =>
                        console.error("Rejected", graphQLErrors, networkError, message,extraInfo)
                )

Dengan hasil ini:

Rejected [] TypeError: current.forEach is not a function
    at /home/richard/Projects/skil/demo-component/node_modules/src/restLink.ts:671:13
    at Array.reduce (<anonymous>)
    at concatHeadersMergePolicy (/home/richard/Projects/skil/demo-component/node_modules/src/restLink.ts:664:23)
    at RestLink.request (/home/richard/Projects/skil/demo-component/node_modules/src/restLink.ts:1235:21)
    at ApolloLink.request (/home/richard/Projects/skil/demo-component/node_modules/apollo-link/src/link.ts:76:19)
    at /home/richard/Projects/skil/demo-component/node_modules/apollo-link/src/link.ts:78:26
    at ApolloLink.request (/home/richard/Projects/skil/demo-component/node_modules/src/ApolloClient.ts:139:16)
    at ApolloLink.request (/home/richard/Projects/skil/demo-component/node_modules/apollo-link/src/link.ts:76:19)
    at /home/richard/Projects/skil/demo-component/node_modules/apollo-link/src/link.ts:78:26
    at DedupLink.request (/home/richard/Projects/skil/demo-component/node_modules/apollo-link-dedup/src/dedupLink.ts:39:30) Network error: current.forEach is not a function undefined

restLink.ts:671 adalah blok kode ini:

export const concatHeadersMergePolicy: RestLink.HeadersMergePolicy = (
  ...headerGroups: Headers[]
): Headers => {
  return headerGroups.reduce((accumulator, current) => {
    if (!current) {
      return accumulator;
    }
    if (!current.forEach) {
      current = normalizeHeaders(current);
    }
    current.forEach((value, key) => {    // <-- This line here
      accumulator.append(key, value);
    });

    return accumulator;
  }, new Headers());
};

https://github.com/apollographql/apollo-link-rest/blob/master/src/restLink.ts#L671

Juga, jika saya mengganti forEach yang gagal dengan ini:

    Object.keys(current).forEach(key => {
      accumulator.append(key, current[key])
    })

Semuanya berfungsi lagi...

Tantangannya , saya tidak mengerti tujuan dari baris di atas:

    if (!current.forEach) {
      current = normalizeHeaders(current);
    }

Karena ini akan selalu gagal, dan selalu mengeksekusi normalizeHeaders() ?

Saya akan mengambil risiko di sini dan menebak bahwa Node mulai kesal dengan penggunaan new Headers() . Instance Header baru memiliki metode forEach pada prototipenya. Jika objek yang dipasok ke pengurangan tidak memiliki metode forEach, kami menjalankan normalizeHeaders . Ini menentukan apakah variabel adalah turunan dari Header. Jika tidak, itu akan menghasilkan satu set tajuk baru, sekali lagi, menggunakan new Headers() , sehingga menyebabkan masalah yang Anda lihat di sini.

Contoh Object.keys(current).forEach() Anda berfungsi karena berhasil mengonversi objek biasa menjadi array, memungkinkan Anda memanggil .forEach() di atasnya.

Langkah selanjutnya debugging bijaksana...apa hasil dari normalizeHeaders() di aplikasi SSR Anda? Lihatlah apa yang dihasilkannya dan saya kira Anda akan menemukan bahwa itu adalah objek biasa, bukan turunan dari Header.

Sejauh yang saya ketahui, saya tidak percaya SSR telah diuji sepenuhnya (lihat #155) tetapi @fbartho mungkin dapat menjelaskan lebih lanjut tentang ini.

SSR bukanlah fitur yang diuji atau didukung secara langsung saat ini. Rasional: jika Anda memiliki SSR, Anda dapat menggunakan server Apollo GraphQL Anda sendiri, dan Anda tidak perlu istirahat tautan

Namun, beberapa orang telah mengetahuinya. Dan saya tidak keberatan dengan PR yang memperbaiki keadaan dunia di sana. Tampaknya bagi saya bahwa kita mungkin hanya membutuhkan tutorial SSR.

Selain itu, relatif umum untuk melakukan polyfill Header tergantung pada lingkungan runtime Anda. Sudahkah Anda mencobanya? @Richard87

Tanggapan @ tombarton benar: tujuan kode itu adalah untuk mengubah hash header menjadi kelas Header yang sesuai.

Halo semua!

Terima kasih atas perhatiannya pada masalah saya;)

Bagian bawah index.js saya adalah ini:

if (global.Headers == null) {
    global.Headers = require("fetch-headers");
}

// Set up babel to do its thing... env for the latest toys, react-app for CRA
// Notice three plugins: the first two allow us to use import rather than require, the third is for code splitting
// Polyfill is required for Babel 7, polyfill includes a custom regenerator runtime and core-js
require('@babel/polyfill');
require('@babel/register')({
    ignore: [/\/(build|node_modules)\//],
    presets: ['@babel/preset-env', '@babel/preset-react'],
    plugins: [
        '@babel/plugin-syntax-dynamic-import',
        '@babel/plugin-proposal-class-properties',
        '@babel/plugin-transform-instanceof',
    ]
});

// Now that the nonsense is over... load up the server entry point
require('./server');

Jadi saya cukup yakin saya memiliki polyfill Header (juga tanpa global.Headers saya mendapat banyak masalah lain)...

Saya sudah memiliki server GraphQL yang berjalan sangat terintegrasi dalam Aplikasi PHP saya (API-Platform + https://webonyx.github.io/graphql-php/) Jadi saya tidak ingin menginstal Server Apollo GraphQL tambahan, saya hanya ingin untuk memuat aplikasi React lebih cepat :D

Saya kesulitan men-debug restLink.ts, tetapi saya telah memasukkan beberapa console.log strategis tetapi current _tampaknya menjadi objek rencana, tetapi console.log mungkin kehilangan beberapa informasi ...

Sunting...

export const concatHeadersMergePolicy: RestLink.HeadersMergePolicy = (
  ...headerGroups: Headers[]
): Headers => {
  return headerGroups.reduce((accumulator, current) => {
    if (!current) {
      return accumulator;
    }

    console.log(current.constructor.name)
    if (!current.forEach) {
      current = normalizeHeaders(current);
    }
    console.log(current.constructor.name)

    Object.keys(current).forEach(key => {
      accumulator.append(key, current[key])
    })

    return accumulator;
  }, new Headers());
};

Mencetak "Header" dua kali...

console.log(current.forEach) mencetak Tidak terdefinisi apa pun yang terjadi, sepertinya polyfill Header saya tidak memiliki properti forEach ?

PHPStorm saya memberi tahu saya headers memiliki metode forEach, tetapi ketika menjalankan kode ini di node saya mendapatkan headers.forEach is not a function :

const Headers = require("fetch-headers");
const headers = new Headers();

console.log(headers)
console.log(headers.forEach)
console.log(!headers.forEach)

headers.forEach(h => console.log(h))

Keluaran:

node /home/richard/Projects/demo-component/src/test.js 
Headers {}
undefined
true
/home/richard/Projects/demo-component/src/test.js:10
headers.forEach(h => console.log(h))
        ^

TypeError: headers.forEach is not a function
    at Object.<anonymous> (/home/richard/Projects/demo-component/src/test.js:10:9)
    at Module._compile (internal/modules/cjs/loader.js:688:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
    at Module.load (internal/modules/cjs/loader.js:598:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
    at Function.Module._load (internal/modules/cjs/loader.js:529:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:741:12)
    at startup (internal/bootstrap/node.js:285:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:739:3)

Menambahkan ini di file bootstrap saya menyelesaikan semua masalah saya: D

if (global.Headers == null) {
    const fetch = require('node-fetch');
    global.Headers = fetch.Headers;
}

perhatikan menggunakan node-fetch alih-alih fetch-headers menyelesaikan masalah!

Apakah halaman ini membantu?
0 / 5 - 0 peringkat