Привет!
У меня есть запрос graphql @rest
, который отлично работает в разработке/браузере, но когда я запускаю тот же код на сервере (SSR), он завершается с длинным загадочным сообщением об ошибке.
(если я отключу директиву @rest
, все остальное работает без нареканий, как в браузере, так и в SSR).
Трассировка стека:
(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.
Пожалуйста посоветуй :/
Еще немного копания, я просто пытаюсь выполнить запрос в NodeJS, не беспокоясь о SSR и т. д.,
и есть этот код:
client
.query({query: Site, variables: {domain: "demo.example.com"}})
.then(
() => console.log("Fullfilled"),
({graphQLErrors, networkError, message, extraInfo}) =>
console.error("Rejected", graphQLErrors, networkError, message,extraInfo)
)
С этим результатом:
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
— это блок кода:
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
Кроме того, если я заменю forEach
на это:
Object.keys(current).forEach(key => {
accumulator.append(key, current[key])
})
Все снова работает...
Задача , я не понимаю цель строк выше:
if (!current.forEach) {
current = normalizeHeaders(current);
}
Так как это всегда будет терпеть неудачу и всегда выполнять normalizeHeaders()
?
Я собираюсь пойти на риск и предположить, что Node расстраивается из-за использования new Headers()
. Новый экземпляр Headers имеет метод forEach
в своем прототипе. Если в объекте, предоставленном для сокращения, отсутствует метод forEach, мы выполняем normalizeHeaders
. Это определяет, является ли переменная экземпляром заголовков. Если нет, он снова сгенерирует новый набор заголовков, используя new Headers()
, что вызовет проблему, которую вы видите здесь.
Ваш пример Object.keys(current).forEach()
работает, потому что он успешно преобразует простой объект в массив, что позволяет вам вызывать на нем .forEach()
.
Следующий шаг отладки... каков результат normalizeHeaders()
в вашем приложении SSR? Взгляните на то, что он выводит, и я предполагаю, что вы обнаружите, что это обычный объект, а не экземпляр заголовков.
Насколько я знаю, я не верю, что SSR был полностью протестирован (см. № 155), но @fbartho , вероятно, может пролить больше света на это.
В настоящее время функция SSR не тестируется и не поддерживается напрямую. Обоснование: если у вас есть SSR, вы можете развернуть свой собственный сервер Apollo GraphQL, и вам не нужен link-rest
Однако кое-кто догадался. И я не возражаю против пиара, улучшающего там состояние мира. Мне кажется, что нам, возможно, просто нужен учебник по SSR.
Кроме того, относительно часто требуется полифиллировать заголовки в зависимости от вашей среды выполнения. Вы уже пробовали это? @ Ричард87
Ответ @tombarton правильный: цель этого кода - преобразовать хэши заголовков в соответствующий класс заголовков.
Всем привет!
Спасибо за внимание к моей проблеме ;)
Нижняя часть моего index.js
такова:
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');
Так что я почти уверен, что у меня есть полифилл заголовка (также без global.Headers
у меня есть куча других проблем)...
У меня уже есть сервер GraphQL, тесно интегрированный в мое приложение PHP (API-платформа + https://webonyx.github.io/graphql-php/). Поэтому я не хочу устанавливать дополнительный сервер Apollo GraphQL, я просто хочу чтобы быстрее загрузить приложение React :D
Мне трудно отлаживать restLink.ts, но я добавил несколько стратегических console.log
, но это current
_кажется_ объектом плана, но console.log
может пропустить некоторую информацию ...
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());
};
Выводит "Заголовок" дважды...
console.log(current.forEach)
выводит Undefined несмотря ни на что, кажется, что мой полифилл заголовков не имеет свойства forEach
?
Мой PHPStorm говорит мне, что у headers
есть метод forEach, но при запуске этого кода в узле я получаю 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))
Вывод:
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)
Добавление этого в мой загрузочный файл решило все мои проблемы: D
if (global.Headers == null) {
const fetch = require('node-fetch');
global.Headers = fetch.Headers;
}
обратите внимание, что использование node-fetch
вместо fetch-headers
решило проблему!
Это следует добавить в документы apollo-link-rest. На какой файл мне поднять PR? https://github.com/apollographql/apollo-link-rest/blob/master/README.md , https://github.com/apollographql/apollo-link-rest/blob/master/docs/rest.md или https://github.com/apollographql/apollo-link/blob/master/docs/source/links/rest.md ?
Самый полезный комментарий
Добавление этого в мой загрузочный файл решило все мои проблемы: D
обратите внимание, что использование
node-fetch
вместоfetch-headers
решило проблему!