首页 > 解决方案 > React-router URL,路由节点/快递和文件结构

问题描述

文件结构

.root
|-client
| -build
| -node_modules
| -public
| -src
|  -components
|  -resources
|   -data
|   -images
|   -templates
|-server
| -models
| -public
| -routes
| -server.js

服务器.js

//Required NPM Packages
const express                =         require('express'),
      app                    =         express(),
      cors                   =         require('cors'),
      bodyParser             =         require('body-parser'),
      mongoose               =         require('mongoose'),
      methodOverride         =         require('method-override');

//MongoDB models.
const Product                =         require('./models/Product');

//Routes.
const indexRoute             =         require('./routes/index');
const demoRoute              =         require('./routes/demo');
const bootstrapTemplateRoute =         require('./routes/bootstrapTemplate');

//Port.
const _PORT = process.env.PORT || 5000;

//Connect to mongoDB.
mongoose.connect({pathToMongoDB}, {useNewUrlParser:true, useUnifiedTopology:true});

//Setup body-parser.
app.use(bodyParser.urlencoded({extended:true}));

//Allow express/node to accept Cross-origin resource sharing.
app.use(cors());

//Set view engine to EJS.
app.set('view engine', 'ejs');

//Change views to specified directory
app.set('views', path.join(__dirname, '..', 'client','src','Resources','templates'));


app.use(express.static(__dirname+"/public"))
app.use(express.static("client/build"));
app.use(express.static("client/Resources/templates"));


//Setup method override.
app.use(methodOverride("_method"));

//register routes to express.
app.use('/', indexRoute);
app.use('/demo', demoRoute);
app.use('/bootstrapTemplate', bootstrapTemplateRoute)

//listen to established port.
app.listen(_PORT, () => {
    console.log(`The server has started on port ${_PORT}!`);
});


module.exports = app;

问题

当我单击后退按钮或在浏览器栏中加载页面时,nodeJS 声明它无法获取该页面。我认识到前端和后端请求是不同的,因为 React-Router 通过它自己的 JavaScript 处理路由,允许零页面重新加载,但是你如何真正解决 nodeJS/Express 上的问题?

此外,当我转到 localhost:3000/demo 时,它会从我的 mongoDB 返回数据并以 json 格式呈现它,而不是加载正确的页面。

目前正在使用以下 Nginx 基本路由配置开发 MERN 堆栈。

http{

    server{
        listen 3000;
        root pathToRoot/client/build;

        location / {
            proxy_pass http://localhost:5000/;
        }
            
    }
}

events {

}

我相信问题出在我通过 express/nodejs 的路由中。我无法创建明确的特定路线并呈现正确的页面,因为 react 正在为我呈现它。我查看了以下问题React-router urls don't work when refresh or writing manual。我应该只做一个全面的并重新路由回主索引页面吗?这似乎会使书签无法使用。

编辑

这是2个节点路由。

index.js

const express                = require('express'),
      router                 = express.Router();


router.get("/", (req,res) => {
    //Render index page.
    res.render("index");
});

演示.js

 const express = require('express'),
      router = express.Router();

const Product = require('../models/Product');


router.get('/:searchInput', (req,res) => {
      Product.find({ $text: {$search: req.params.searchInput}}, (err,foundItem) => {
            if(err){
                  console.log(err);
            }else{
                  res.send(foundItem);
            }            
      })
})

router.get('/', (req, res) => {     
      Product.find({}, (err, foundItem) => {
            res.send(foundItem);
      });
});


module.exports = router;

标签: javascriptnode.jsreactjsexpress

解决方案


我会尝试将你的开发文件夹从你的构建文件夹中分离出来,因为一旦你开始运行它会变得有点混乱react build。我使用的结构是:

api  build  frontend  run_build.sh

api文件夹包含我的 express server 开发,frontend包含我的 react 开发,并且build是从run_build.sh脚本创建的,它看起来像这样。

#!/bin/bash
rm -rf build/

# Build the front end
cd frontend
npm run build

# Copy the API files
cd ..
rsync -av --progress api/ build/ --exclude node_modules

# Copy the front end build code
cp -a frontend/build/. build/client/

# Install dependencies
cd build
npm install

# Start the server
npm start

现在在您的build目录中,您应该有一个子文件夹client,其中包含您的反应代码的构建版本,没有任何混乱。要告诉 express 使用某些路由进行反应,请在 expressserver.js文件中添加以下内容。

注意在添加反应路由之前先添加你的 express api 路由,否则它将不起作用。

// API Routing files - Located in the routes directory // 
var indexRouter         = require('./routes/index')
var usersRouter         = require('./routes/users');
var oAuthRouter         = require('./routes/oauth');
var loginVerification   = require('./routes/login_verification')

// API Routes //
app.use('/',indexRouter);
app.use('/users', usersRouter);
app.use('/oauth',oAuthRouter);
app.use('/login_verification',loginVerification);

// React routes - Located in the client directory // 
app.use(express.static(path.join(__dirname, 'client'))); // Serve react files
app.use('/login',express.static(path.join(__dirname, 'client')))
app.use('/welcome',express.static(path.join(__dirname, 'client')))

组件文件中的 reactApp函数App.js将如下所示,定义您刚刚添加的路由,告诉 express 用于 react。

function App() {
  return (
   <Router>
     <div className="App">
      <Switch>
        <Route exact path="/login" render={(props)=><Login/>}/>
        <Route exact path="/welcome" render={(props)=><Welcome/>}/>
      </Switch>
     </div>
   </Router> 
  );
}

在 components 文件夹下有 和 的login组件welcome。现在导航到http://MyWebsite/login将提示 express 使用 react 路由,而例如导航到http://MyWebsite/login_verification将使用 express API 路由。


推荐阅读