node.js - 使用 Apollo 进行服务器端渲染 : getaddrinfo ENOTFOUND

标签 node.js express react-router apollo react-apollo

我正在使用 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/

相关文章:

node.js - 使用 Node.js 进行 Sequelize 的可扩展播种?

json - 尝试在不使 Node.js 服务器崩溃的情况下解析 JSON

javascript - 如何在 Express/Node Controller 中确定数据范围

JavaScript Map.get(variableName) 返回未定义

node.js - 通过 JavaScript 响应式(Reactive)扩展使用 Mongoose Stream

validation - 对铁路模型进行验证

node.js - Express默认使用集群吗?

javascript - 使用 node.js 上传文件时出错

javascript - React-Router:如何测试渲染链接的 href?

javascript - React 将 prop 传递给组件返回 undefined