2017-10-23 28 views
6

Tôi có máy chủ tốc hành đang chạy để hiển thị trước ứng dụng phản ứng của mình. Tôi đã có một tập tin tuyến đường phù hợp với HomeContainer đến tuyến đường cơ sở / và tất cả các tuyến đường khác phù hợp với trang không tìm thấy.Hiển thị bên máy chủ Express.js - Yêu cầu '/ json/version/

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; 

Vấn đề tôi gặp phải là khi tôi chạy ứng dụng trên máy chủ, tuyến đường không tìm thấy trang được hiển thị trước khi nhanh chóng chuyển sang tuyến HomeContainer.

Tôi đã xác định rằng điều này xảy ra vì máy chủ tốc độ của tôi yêu cầu /json/version trước khi yêu cầu /, tuyến đường này không khớp với một trong tệp tuyến đường của tôi và do đó thành phần trang không tìm thấy được hiển thị .

Bây giờ những gì tôi không nhận được là lý do tại sao nó đưa ra yêu cầu này và cách dừng thành phần page not found được hiển thị trước vùng chứa nhà. Tôi đã thử gỡ lỗi máy chủ nút và vị trí sớm nhất mà tôi có thể tìm thấy đường dẫn này đang được tham chiếu trong cuộc gọi phát ra bên trong tệp có tên _http_server.js

Dưới đây là ảnh chụp màn hình của trình gỡ rối và nơi tôi tìm thấy URL đang được tham chiếu.

Debugger Screenshot

Ngoài ra để tham khảo, tôi đã bao gồm máy chủ tốc hành của mình bên dưới.

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'); 
}); 

Có ai biết tại sao điều này xảy ra và cách tôi giải quyết được sự cố của mình?

EDIT: Dưới đây là một đoạn video cho thấy vấn đề này - https://d26dzxoao6i3hh.cloudfront.net/items/2z3y3f1x3N1D2e422W42/Screen%20Recording%202017-10-23%20at%2012.24%20pm.mov

+0

Ra quan tâm, giả sử bạn đang sử dụng phản ứng-router, phiên bản nào là nó? – jthawme

+0

@jthawme Tôi và phiên bản 4 – woolm110

+0

điều gì sẽ xảy ra nếu bạn chạy nó mà không có JavaScript? Tôi nghĩ điều gì xảy ra là máy chủ của bạn trả về 'Trang không tìm thấy', nhưng ngay khi JS khởi động nó tải dữ liệu thích hợp và xây dựng lại DOM. Tôi cho rằng bạn có một vấn đề trong routeComponentPromises. –

Trả lời

0

Không phải 100% chắc chắn về những gì đã gây ra vấn đề nhưng bây giờ tôi đã cố định nó.

Hai thay đổi lớn tôi làm là

  1. Sử dụng EJS như một công cụ khuôn mẫu
  2. Thiết indexFromEmptyFile false trong plugin gzip

Số 2 có vẻ là thực sự quan trọng, mà không có nó express đang cố gắng phân phối index.html thay vì index.ejs và điều này đã gây ra cùng một vấn đề như trên như index.html không khớp với tuyến đường trong tệp tuyến đường của tôi.

Dưới đây là cập nhật mã

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'); 
});` 
Các vấn đề liên quan