【发布时间】:2017-12-02 13:58:21
【问题描述】:
我正在使用 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();
});
});
});
它使用来自 React Router v3 的 match() 函数(如从文档链接的“GitHunt”示例中的 package.json 所证明的那样)。我正在使用没有match() 的React Router v4,所以我使用react-router-config package 中的renderRoutes() 重构代码如下。
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: 未处理的承诺 拒绝(拒绝 id:1):错误:网络错误:请求 http://localhost:3000 失败,原因:getaddrinfo ENOTFOUND localhost 本地主机:3000
或
(node:8691) UnhandledPromiseRejectionWarning: 未处理的承诺 拒绝(拒绝 id:1):错误:网络错误:请求 http://localhost:3000失败,原因:socket挂断
我已经为这个问题苦苦挣扎了几个小时,但似乎无法弄清楚。 similar problem 的解决方案似乎与本案无关。任何帮助将不胜感激!
更多信息
如果我不杀死 nodemon 服务器,一段时间后我会收到数千个以下错误:
POST / - - 毫秒 - -
(节点:1938)UnhandledPromiseRejectionWarning: 未处理的承诺拒绝(拒绝 id:4443):错误:网络 错误:对http://localhost:3000的请求失败,原因:socket挂断
但是,如果我确实终止了服务器,我会立即收到此错误:
/Users/.../node_modules/duplexer/index.js:31
writer.on("drain", function() { ^TypeError:无法读取未定义的“on”属性
在双工 (/Users/.../node_modules/duplexer/index.js:31:11)
在 Object.module.exports (/Users/.../node_modules/stream-combiner/index.js:8:17)
在 childrenOfPid (/Users/.../node_modules/ps-tree/index.js:50:6)
在 kill (/Users/.../node_modules/nodemon/lib/monitor/run.js:271:7)
在 Bus.onQuit (/Users/.../node_modules/nodemon/lib/monitor/run.js:327:5)
在 emitNone (events.js:91:20)
在 Bus.emit (events.js:188:7)
在过程中。 (/Users/.../node_modules/nodemon/lib/monitor/run.js:349:9)
在 Object.onceWrapper (events.js:293:19)
在 emitNone (events.js:86:13)
另外,端口 3000 是正确的。如果我更改数字,则会收到不同的错误:
(node:2056) UnhandledPromiseRejectionWarning: 未处理的承诺 拒绝(拒绝 id:1):错误:网络错误:请求 http://localhost:3010 失败,原因:连接 ECONNREFUSED 127.0.0.1:3010
【问题讨论】:
-
你试过
http://127.0.0.1:3000而不是localhost吗?此外,您应该排除防病毒软件和/或防火墙。并确保在您的 hosts 文件中有一个条目127.0.0.1 localhost。 -
我尝试了
127.0.0.1和localhost,有和没有http://,但事实并非如此。我还仔细检查了主机文件中的条目。但是我注意到问题仅在直接访问子文件夹并相应更新问题时才会显现出来。谢谢 -
将 ssrMode: true 添加到 ApolloClient,我遇到了类似的问题,根本原因是重复获取。希望对您有所帮助。
-
您的意思是
const client = new ApolloClient(/* ... */)?因为我已经在其中包含了ssrMode: true,所以我只是省略了第二个代码 sn-p 中的参数,因为它们与第一个代码中的参数相同。还是谢谢! -
你使用的node版本和操作系统是什么?
标签: node.js express react-router apollo react-apollo