首页 > 解决方案 > 使用 Express API 和 ReactJS SPA 进行路由

问题描述

我最近在 Heroku 上使用 React 部署了一个站点。在浏览器的控制台中,我收到了 html 文本的输出,而不是我的用户界面 javascript。

链接到我的站点 链接到存储库

我认为问题的根源在于我的 server.js 路由为我的 index.html 提供服务

服务器.js

// Allows us to place keys and sensitive info in hidden .env file
require("dotenv").config();

// Require Packages
const express = require("express");
const app = express();
const morgan = require("morgan")
const db = require("./models");
const routes = require("./routes");
const passport = require("passport");
const session = require("express-session")
const path = require("path");

const MySQLStore = require("express-mysql-session")(session);

require("./config/passport")(passport)
app.use(express.urlencoded({ extended: true }));
app.use(express.json());

let options = {};
if (process.env.NODE_ENV === 'production') {
    options = {
        host: process.env.HOST,
        port: 3306,
        user: process.env.USER,
        password: process.env.PASSWORD,
        database: process.env.DB
    }
} else {
    options = {
        host: 'localhost',
        port: 3306,
        user: 'root',
        password: process.env.DB_PASSWORD,
        database: 'tracker'
    }
}


// Options for mysql session store

let sessionStore = new MySQLStore(options);

// Pass in mysql session store
app.use(session({
    key: 'surfing_dogs',
    secret: 'surfing_dogs',
    store: sessionStore,
    resave: false,
    saveUninitialized: false
}))

app.use(passport.initialize());
app.use(passport.session());

app.use(morgan('common'))


// THIS IS REALLY IMPORTANT FOR ROUTING CLIENT SIDE
// We want to have our app to use the build directory 
app.use(express.static(__dirname + '/client/build'))

// For every url request we send our index.html file to the route
app.get("/*", (req, res) => {
    res.sendFile(path.join(__dirname, "client", "build", "index.html"));
});

app.use(routes)


db.sequelize.sync({ force: false }).then(() => {
    let server = app.listen(process.env.PORT || 5000, function () {
        let port = server.address().port;
        console.log(`Server is listening on PORT ${port}`)
    })
})

详细地说,我将此路由放在我的 server.js 中,因为我有客户端路由,并且我想欺骗浏览器始终为 index.html 提供服务

我想解决这个问题的另一个原因是我目前无法使用凭据登录我的网站。

这是前端明智的登录过程的一小部分。我的目标是基于登录状态,但不幸的是登录状态没有改变。

 if (this.state.loggedIn === true) {
      return (
        <Router>
          <Navbar user={this.state.user} logout={this.logout} />
          <Switch>
            {this.state.userType === 'administrator' ? <Route path='/' exact component={() => <AdminHome user={this.state.user} />} /> : ''}
            {this.state.userType === 'instructor' ? <Route path='/' exact component={() => <InstructorHome user={this.state.user} />} /> : ''}

            {/* Path for student profile based on it */}
            <Route exact path='/student/:id' exact component={StudentProfile} />

            {this.state.userType === 'student' ? <Route path='/' exact component={() => <StudentHome user={this.state.user} />} /> : ''}
            <Route exact path='/settings' exact component={() => <Settings user={this.state.user} />} />
            <Route component={NoPage} />
          </Switch>
        </Router>
      )
    } else {
      return (
        <Router>
          <Switch>
            <Route path='/' exact component={SplashPage} />
            <Route path='/login' exact component={Login} />
            <Route path='/signup' exact component={Signup} />

            {/* Go to signup based on cohortID */}
            <Route path='/signup/:id' exact component={CohortSignup} />

            <Route component={NoPage} />

          </Switch>
        </Router>
      )
    }

希望那里有人可以帮助我!

标签: javascriptnode.jsreactjsexpressheroku

解决方案


在查看了 server.js 的存储库后,您将所有到达服务器的流量(甚至是您自己的 api 请求)发送到前端。

首先确保您的服务器端路由以可区分的内容开头,例如

app.get('/api/*',(req,res)=>/*somecode*/)

这是因为如果您的服务器也是前端中的一条路由,那么您的服务器会混淆诸如“/ login”之类的内容,并且最终只会根据定义的时间来提供一个或另一个。

然后更新你的 server.js 以匹配它,它应该可以工作:

//API Requests handled first
require('./routes')(app);

//Non api requests in production
if (process.env.NODE_ENV === 'production') {
    app.use([someProductionMiddleware()])
    // Express will serve up production assets i.e. main.js
    app.use(express.static('client/build'));
    // If Express doesn't recognize route serve index.html
    const path = require('path');
    app.get('*', (req, res) => {
        res.sendFile(
            path.resolve(__dirname, 'client', 'build', 'index.html')
        );
    });
}

推荐阅读