React Router 在生产环境中不匹配 path = "/"

React Router doesnot match path = "/" in production

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

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

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

但请尝试在 url 的末尾添加 /{anything},例如https://portfolio-website.azurewebsites.net/x,网站加载完美。 React 路由器没有捕捉到路径“/”,这确实令人困惑,但是当您转到大约 link 然后单击主页时,站点会加载主页。

我目前正在使用 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, isLandscape, overflowHidden]);

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

  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 提供 react 静态文件:

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

但问题是:react public 文件夹中有一个静态 index.html 文件。这就是为什么您在 root 上看到空白页的原因。它是 react public 文件夹中的静态 index.html 文件,它不包含 react 脚本标签。 react-scripts 使用它并将 react <script src="..."> 标签附加到它。所以你不能删除它。而是在提供静态文件之前为 root 设置一个指向反应的路由:

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