我正在使用 Express 运行 Apollo/React,并且正在尝试让服务器端渲染正常工作。 Apollo docs建议使用以下初始化代码来连接 API 服务器:
app.use((req, res) => {
match({ routes, location: req.originalUrl }, (error, redirectLocation, renderProps) => {
const client = new ApolloClient({
ssrMode: true,
networkInterface: createNetworkInterface({
uri: 'http://localhost:3000', // Instead of 3010
opts: {
credentials: 'same-origin',
headers: {
cookie: req.header('Cookie'),
},
},
}),
});
const app = (
<ApolloProvider client={client}>
<RouterContext {...renderProps} />
</ApolloProvider>
);
getDataFromTree(app).then(() => {
const content = ReactDOM.renderToString(app);
const initialState = {[client.reduxRootKey]: client.getInitialState() };
const html = <Html content={content} state={initialState} />;
res.status(200);
res.send(`<!doctype html>\n${ReactDOM.renderToStaticMarkup(html)}`);
res.end();
});
});
});
它使用 match()
React Router v3 中的函数(如文档链接的“GitHunt”示例中的 package.json 所示)。我正在使用 React Router v4,其中 match()
不存在,所以我将代码重构如下,使用 renderRoutes()
来自 react-router-config
package .
app.use((req, res) => {
const client = new ApolloClient(/* Same as above */)
const context = {}
const app = (
<ApolloProvider client={client}>
<StaticRouter context={context} location={req.originalUrl}>
{ renderRoutes(routes) }
</StaticRouter>
</ApolloProvider>
)
getDataFromTree(app).then(/* Same as above */)
})
我的理解是<StaticRouter>
避免使用 match()
。然而react-router-config
提供 matchRoutes()
如果需要的话,它似乎提供了类似的功能(尽管没有回调)。
当我访问http://localhost:3000时,页面按预期加载,我可以跟踪子目录的链接(例如 http://localhost:3000/folder )。 当我尝试通过在地址栏中输入名称来直接加载子目录时,我的浏览器会一直等待服务器响应。大约六秒后,终端显示以下错误之一(不确定是什么导致错误在后续尝试中发生变化):
(node:1938) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Network error: request to http://localhost:3000 failed, reason: getaddrinfo ENOTFOUND localhost localhost:3000
或
(node:8691) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Network error: request to http://localhost:3000 failed, reason: socket hang up
我已经为这个问题苦苦挣扎了几个小时,但似乎无法弄清楚。 similar problem的解决方案似乎与本案无关。任何帮助将不胜感激!
更多信息
如果我不终止 nodemon 服务器,一段时间后我会收到数千个以下错误:
POST / - - ms - -
(node:1938) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 4443): Error: Network error: request to http://localhost:3000 failed, reason: socket hang up
但是,如果我确实终止了服务器,我会立即收到此错误:
/Users/.../node_modules/duplexer/index.js:31
writer.on("drain", function() { ^
TypeError: Cannot read property 'on' of undefined
at duplex (/Users/.../node_modules/duplexer/index.js:31:11)
at Object.module.exports (/Users/.../node_modules/stream-combiner/index.js:8:17)
at childrenOfPid (/Users/.../node_modules/ps-tree/index.js:50:6)
at kill (/Users/.../node_modules/nodemon/lib/monitor/run.js:271:7)
at Bus.onQuit (/Users/.../node_modules/nodemon/lib/monitor/run.js:327:5)
at emitNone (events.js:91:20)
at Bus.emit (events.js:188:7)
at process. (/Users/.../node_modules/nodemon/lib/monitor/run.js:349:9)
at Object.onceWrapper (events.js:293:19)
at emitNone (events.js:86:13)
此外,端口 3000 是正确的。如果我更改数字,则会收到不同的错误:
(node:2056) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Network error: request to http://localhost:3010 failed, reason: connect ECONNREFUSED 127.0.0.1:3010
最佳答案
您是否在一个或多个容器内运行服务器/项目。我遇到了与此相同的问题,并最终执行了以下操作来解决它。
const networkInterface = createNetworkInterface({
uri:进程.浏览器
? 'http://0.0.0.0:1111/graphql'
:'http://my-docker-container-name:8080/graphql'
})
我在 docker-compose.yml 中为容器创建了一个内部 docker 网络,该网络允许容器相互通信,但是浏览器通过不同的 URL 与 GQL 服务器通信,从而导致您所描述的问题SSR getaddrinfo ENOTFOUND,因此虽然它在客户端工作,但在 SSR 上它会失败。
我正在使用 nextJS 框架,它能够检测浏览器或 SSR,我确信您可以在 nextJS 之外执行相同的操作。
关于node.js - 使用 Apollo 进行服务器端渲染 : getaddrinfo ENOTFOUND,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44815430/