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"));
}
加载此站点: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"));
}