在生产环境中,React Router与路径=“ /”不匹配

问题描述

加载此网站:https://portfolio-website.azurewebsites.net/

预期行为:正确加载网站内容

实际行为:您会看到一个空白的页面,没有任何内容

但是请尝试在网址末尾添加/ {anything},例如https://portfolio-website.azurewebsites.net/x,该网站可以完美加载。 React Router并没有捕获到真正令人困惑的路径“ /”,但是当您转到about链接然后单击主页时,该站点将加载主页。

我当前正在使用azure,但是在heroku中也是如此。救命!

您可以在此处查看源代码并在此处做出贡献:https://github.com/CrestNiraj12/portfolio-website

App.js

const App = ({ page,overflowHidden,isLandscape,dialogShow,loading }) => {
  useEffect(() => {
    if (overflowHidden) document.body.style.overflow = "hidden";
    else document.body.style.overflow = "visible";

    isLandscape(window.innerWidth > window.innerHeight);
  },[page,overflowHidden]);

  const routes = [
    { path: "/",Component: Home,isExact: true },{ path: "/about",Component: About,isExact: false },{ path: "/update/posts/:postId",Component: EditPost,{ path: "/posts/:postPath",Component: Post,{ path: "/auth/login",Component: Login,{ path: "/auth/register",Component: Signup,{
      path: "/auth/password/recover",Component: ConfirmRecoverPassword,isExact: false,},{ path: "/user/dashboard",Component: Dashboard,{ path: "/posts",Component: Posts,{ path: "/users",Component: Users,{ path: "/user/addpost",Component: AddPost,{ path: "/user/confirm/:token",Component: ConfirmMail,{
      path: "/password/recover/token/:token",Component: ResetPassword,{ path: "/*",];

  return (
    <>
      <Flash />
      {dialogShow && <Dialog />}

      {loading && <Preloader />}
      <Router history={createbrowserHistory()}>
        {[HOME,ABOUT,ALL_POSTS,POST].includes(page) && <Navbar />}
        <Switch>
          {routes.map(({ path,Component,isExact }) => (
            <Route
              key={path}
              path={path}
              exact={isExact}
              component={Component}
            />
          ))}
        </Switch>
      </Router>
    </>
  );
};

Server.js

const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const passport = require("./backend/config/passport");
const session = require("express-session");
const MongoStore = require("connect-mongo")(session);
const helmet = require("helmet");
const path = require("path");

require("dotenv").config({
  path: `.env.${process.env.NODE_ENV.trim() || "development"}`,});

const app = express();
const port = process.env.PORT || 5000;

const postsRouter = require("./backend/routes/posts");
const usersRouter = require("./backend/routes/users");
const authenticationRouter = require("./backend/routes/authentication");

app.use(cors());
app.use(helmet());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static(__dirname + "/client/public"));

const url = process.env.CONNECTION_URL;

mongoose
  .connect(url,{
    auth: {
      user: process.env.DB_USER,password: process.env.DB_PASS,useNewUrlParser: true,useCreateIndex: true,useUnifiedTopology: true,useFindAndModify: false,})
  .catch((err) => console.log(err));

const connection = mongoose.connection;

const sessionStore = {
  name: "authSession",secret: process.env.SESSION_SECRET,resave: false,saveUninitialized: true,cookie: { httpOnly: true },store: new MongoStore({
    mongooseConnection: connection,secret: process.env.STORE_SECRET,ttl: 24 * 60 * 60 * 1000,autoRemove: "interval",autoRemoveInterval: 10,}),};

if (process.env.NODE_ENV === "production") {
  const hour = 24 * 60 * 60 * 1000;
  app.set("trust proxy",1);
  sessionStore.cookie.secure = true;
  sessionStore.cookie.maxAge = hour;
  sessionStore.cookie.expires = new Date(Date.Now() + hour);
}

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

app.use("/posts",postsRouter);
app.use("/user",usersRouter);
app.use("/auth",authenticationRouter);

connection
  .once("open",() => {
    console.log("Established database connection!");
  })
  .catch((err) => console.log(err));

if (process.env.NODE_ENV === "production") {
  app.use(express.static("client/build"));
  app.get("/*",(req,res) => {
    res.sendFile(path.resolve(__dirname,"client","build","index.html"));
  });
}

app.listen(port,() => console.log("Server running on port: " + port));

服务器端package.json

{
  "name": "portfolio-website","version": "1.0.0","description": "My Personal website","main": "server.js","repository": {
    "type": "git","url": "https://github.com/CrestNiraj12/portfolio-website.git"
  },"scripts": {
    "start": "NODE_ENV=production node server","azure": "NPM_CONfig_PRODUCTION=false npm run imagemin && npm install --prefix client && npm run build --prefix client","imagemin": "imagemin client/src/images/*.{jpg,png,gif} --out-dir=client/src/images","dev": "concurrently \"nodemon server\" \"cd client && npm start\" \"cd client && npm run watch-sass\"","serve": "serve -s client/build"
  },"author": "Niraj Shrestha","license": "ISC","engines": {
    "node": ">=12.0.0","npm": ">=6.0.0"
  },"dependencies": {
    "bcryptjs": "^2.4.3","connect-mongo": "^3.2.0","cors": "^2.8.5","dotenv": "^8.2.0","express": "^4.17.1","express-session": "^1.17.1","express-validator": "^6.6.0","helmet": "^3.23.3","imagemin-cli": "^6.0.0","lodash": "^4.17.19","mongoose": "^5.9.22","multer": "^1.4.2","nodemailer": "^6.4.11","nodemailer-smtp-transport": "^2.7.4","passport": "^0.4.1","passport-local": "^1.0.0"
  },"devDependencies": {
    "concurrently": "^5.3.0","nodemon": "^2.0.4","serve": "^11.3.2"
  }
}

解决方法

在设置reactjs路由之前,您要使用express服务提供静态文件:

app.use(express.static(__dirname + "/client/public"));
...
app.get("/*",(req,res) => {
  res.sendFile(path.resolve(__dirname,"client","build","index.html"));
});

但是问题是:react公用文件夹中有一个静态index.html文件。这就是为什么您在根目录上看到空白页的原因。它是react公共文件夹中的静态index.html文件,并且不包含react脚本标签。 react-scripts使用它,并将react <script src="...">标签附加到它。因此您无法将其删除。而是在提供静态文件之前为root设置一个指向进行响应的路由:

app.get("/",res) => { // the root
  res.sendFile(path.resolve(__dirname,"index.html"));
}
...
app.use(express.static(__dirname + "/client/public")); // serving static files
...
app.get("/*",res) => { // all remaining addresses
  res.sendFile(path.resolve(__dirname,"index.html"));
}