Express.js服务器端渲染 - 请求'/ json / version /

时间:2017-10-23 11:10:08

标签: javascript json node.js reactjs express

我已经运行了一个快速服务器来预渲染我的反应应用程序。我有一个路由文件,它匹配HomeContainer到基本路由/,所有其他路由匹配到找不到的页面。

import HomeContainer from 'containers/home-container/home-container';
import PageNotFound from 'components/page-not-found/page-not-found';

const routes = [
  {
    path: '/',
    exact: true,
    component: HomeContainer
  },
  {
    path: '*',
    component: PageNotFound
  }
];

export default routes;

我遇到的问题是当我在服务器上运行应用程序时,未找到的页面路由会在快速更改为HomeContainer路由之前呈现。

我发现这是因为我的快递服务器在向/json/version发出请求之前向/发出请求,此路由与我的路由文件中的路由不匹配,因此找不到页面未找到的组件。

现在我没有得到的是为什么它正在发出这个请求以及如何停止在主容器之前呈现的page not found组件。我已经尝试调试节点服务器和最早的地方我可以找到这个被引用的路径在一个名为_http_server.js

的文件内的一个emit调用中

下面是调试器的屏幕截图,我找到了引用的URL。

Debugger Screenshot

另外作为参考,我在下面加入了我的快递服务器。

import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import { StaticRouter, matchPath } from 'react-router-dom';
import serialize from 'serialize-javascript';
import expressStaticGzip from 'express-static-gzip';
import sourceMapSupport from 'source-map-support';

import routes from 'routes';
import configureStore from 'store';
import AppContainer from 'containers/app-container/app-container';

if (process.env.NODE_ENV === 'development') {
  sourceMapSupport.install();
}

const app = express();

app.use(expressStaticGzip('./static/assets'));

app.get('*', (req, res, next) => {
  const store = configureStore();

  /**
   * Load initial data into state
   * match requested URL path to the component in routes
   * check for 'fireInitialActions' method (found in the container components)
   * and dispatch if it exists
   */
  const routeComponentPromises = routes.reduce((accumulator, route) => {
    if (matchPath(req.url, route) && route.component && route.component.fireInitialActions) {
      accumulator.push(Promise.resolve(store.dispatch(route.component.fireInitialActions())));
    }

    return accumulator;
  }, []);

  Promise.all(routeComponentPromises)
    .then(() => {
      const context = {};
      const markup = renderToString(
        <Provider store={store}>
          <StaticRouter location={req.url} context={context}>
            <AppContainer />
          </StaticRouter>
        </Provider>
      );

      const initialData = store.getState();
      res.send(`
        <!DOCTYPE html>
        <html>
          <head>
            <title>Test</title>
            <script src='vendor.js' defer></script>
            <script src='app.js' defer></script>
            <script>window.__initialData__ = ${serialize(initialData)}</script>
          </head>
          <body>
            <div id="root">${markup}</div>
          </body>
        </html>
      `);
    })
    .catch(next);
});

app.listen(process.env.PORT || 3000, () => {
  console.log('Server is listening');
});

有谁知道为什么会发生这种情况以及如何解决我的问题?

编辑:这是一个显示问题的视频 - https://d26dzxoao6i3hh.cloudfront.net/items/2z3y3f1x3N1D2e422W42/Screen%20Recording%202017-10-23%20at%2012.24%20pm.mov

2 个答案:

答案 0 :(得分:4)

使用--inspect键运行节点应用程序后,我遇到了同样的问题。 Chrome检查器向/json/json/version发送了这些奇怪的GET请求。

因此,解决方案(就我而言)是:

  1. 转到chrome://inspect
  2. 单击链接“为节点打开专用的DevTools”;
  3. 打开Connection标签。
  4. 从列表中删除端点。

答案 1 :(得分:0)

不是100%确定导致问题的原因,但我现在已经修复了它。

我做的两个主要变化是

  1. 使用EJS作为模板引擎
  2. 在gzip插件中将indexFromEmptyFile设置为false
  3. 第2号似乎非常重要,如果没有明确表示试图提供index.html而不是index.ejs而导致上述问题与index.html不匹配路线文件中的路线。

    以下是更新的代码

    import express from 'express';
    import React from 'react';
    import { renderToString } from 'react-dom/server';
    import { Provider } from 'react-redux';
    import { StaticRouter, matchPath } from 'react-router-dom';
    import serialize from 'serialize-javascript';
    import sourceMapSupport from 'source-map-support';
    import expressStaticGzip from 'express-static-gzip';
    
    import routes from 'routes';
    import configureStore from 'store';
    import AppContainer from 'containers/app-container/app-container';
    
    if (process.env.NODE_ENV === 'development') {
      sourceMapSupport.install();
    }
    
    const app = express();
    
    app.set('views', './static/');
    app.set('view engine', 'ejs');
    app.use(expressStaticGzip('static/assets', { indexFromEmptyFile: false }));
    
    app.get('*', (req, res, next) => {
      const store = configureStore();
    
      /**
       * Load initial data into state
       * match requested URL path to the component in routes
       * check for 'fireInitialActions' method (found in the container components)
       * and dispatch if it exists
       * return as promises so we can chain
       */
      const routeComponentPromises = routes.reduce((accumulator, route) => {
        if (matchPath(req.url, route) && route.component && route.component.fireInitialActions) {
          accumulator.push(Promise.resolve(store.dispatch(route.component.fireInitialActions())));
        }
    
        return accumulator;
      }, []);
    
      Promise.all(routeComponentPromises)
        .then(() => {
          const context = {};
          const markup = renderToString(
            <Provider store={store}>
              <StaticRouter location={req.url} context={context}>
                <AppContainer />
              </StaticRouter>
            </Provider>
          );
    
          const initialData = serialize(store.getState());
    
          res.render('index.ejs', {initialData, markup});
        })
        .catch(next);
    });
    
    app.listen(process.env.PORT || 3000, () => {
      console.log('Server is listening');
    });`