我们目前正在部署一个静态 React 应用程序,由 NodeJS / Express 服务器通过 apache2 反向代理提供服务。应用程序索引工作正常,但如果页面不存在,我尝试重定向,这可以在本地主机上工作,但不能在远程服务器上工作。如果我去
myip/foo
,我会收到
cannot GET /foo
这是我的 server.js :
const express = require("express");
const app = express();
const port = 8080;
const bodyParser = require("body-parser");
const cors = require("cors");
const db = require("./src/models/db.models");
const compression = require("compression");
app.use(bodyParser.json());
app.use(cors());
//Disable x-powered-by header for security reason
app.disable("x-powered-by");
// use compression (gzip etc) for each request to increase perf
app.use(compression());
app.get("/login", (req, res) => {
res.sendFile(__dirname + "/client/index.html");
});
app.get("/signUp/:id", (req, res) => {
res.sendFile(__dirname + "/client/index.html");
});
// force: true will drop the table if it already exists (so drop all the data too)
db.sequelize
.sync()
.then(() => {
console.log("Server Running (*-*)");
})
.catch((err) => console.log("Error ¯_(ツ)_/¯", err));
require("./src/routes/user.routes")(app);
require("./src/routes/auth.routes")(app);
require("./src/routes/pageContents.routes")(app);
require("./src/routes/survey.routes")(app);
require("./src/routes/theme.routes")(app);
require("./src/routes/question.routes")(app);
require("./src/routes/surveyQuestion.routes")(app);
require("./src/routes/surveyHasUser.routes")(app);
require("./src/routes/answer.routes")(app);
require("./src/routes/surveyHasTheme.routes")(app);
// use static folder to render builded front react app
app.use(express.static("client"));
app.listen(port, () => console.log(`Listening on port ${port}`));
这是我的 app.js (前端),在后端文件夹中构建并设置
import './App.css';
import Login from './pages/login/Login.page';
import React from 'react';
import { BrowserRouter, Route, Redirect } from 'react-router-dom';
import Intro from './pages/questionnaire/Intro/Intro.page';
import Edito from './pages/edito/Edito.page';
import Cgu from './pages/cgu/Cgu.page';
import { Switch } from 'react-router-dom';
import Questionnaire from './pages/questionnaire/Questionnaire/Questionnaire.page';
import Remerciement from './pages/questionnaire/Remerciement/Remerciement.page';
import ListeQuestionnaire from './pages/liste/ListeQuestionnaire.page';
import ProtectedRoute from './components/utils/ProtectedRoute.component';
import AuthService from '../src/services/auth.service';
import LogOut from './components/utils/logOut.component';
import TableauDeBord from './pages/tableauDeBord/tableauDeBord.page';
import SignUp from '../src/pages/signUp/signUp.page';
function App() {
return (
<div className="App">
<BrowserRouter>
<Switch>
<ProtectedRoute path="/intro" component={Intro} />
<Route path="/signUp/:token" component={SignUp} />
<Route path="/login" component={() => (AuthService.isAuthenticated() ? <Redirect to="/" /> : <Login />)} />
<ProtectedRoute path="/questionnaire" component={Questionnaire} />
<ProtectedRoute path="/remerciement" component={Remerciement} />
<ProtectedRoute path="/listeQuestionnaire" component={ListeQuestionnaire} />
<ProtectedRoute path="/cgu" component={Cgu} />
<ProtectedRoute path="/logOut" component={LogOut} />
<ProtectedRoute path="/edito" component={Edito} />
<Route path="/:token" component={SignUp} />
<ProtectedRoute path="/" component={TableauDeBord} />
</Switch>
</BrowserRouter>
</div>
);
}
export default App;
最后这是我的 apache 配置文件:
<VirtualHost *:80>
# ServerName domain.com
# ServerAlias www.domain.com
DocumentRoot "/www/html/360-nodejs"
ProxyRequests Off
ProxyPreserveHost On
ProxyVia Full
AllowEncodedSlashes On
ErrorLog "/var/log/apache2error.log"
CustomLog "/var/log/apache2errorcustom.log" common
<Proxy *>
#Require all granted
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
Apache 日志显示,当我们调用
/:id
或 /signUp/:id
时,服务器已关闭,但服务器仍在运行
我可以直接链接到另一个路由,但是如果我刷新页面,我会收到 404,如果我将其写入不再有效的 URL 中,则会收到 404,所以我无法查询像 /:id 这样的直接 URL,因为我也收到了404
嗯,像往常一样,我应该更好的 RTFD。 https://create-react-app.dev/docs/deployment/#serving-apps-with-client-side-routing
如果您使用在底层使用 HTML5 PushState 历史 API 的路由器(例如,带有 browserHistory 的 React Router),许多静态文件服务器将会失败。例如,如果您使用带有 /todos/42 路由的 React Router,开发服务器将正确响应 localhost:3000/todos/42,但服务于上述生产构建的 Express 则不会。
这是因为当 /todos/42 有新页面加载时,服务器会查找文件 build/todos/42 但找不到它。服务器需要配置为通过提供index.html 来响应对/todos/42 的请求。例如,我们可以修改上面的 Express 示例,为任何未知路径提供 index.html:
app.use(express.static(path.join(__dirname, 'build')));
-app.get('/', function (req, res) {
+app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
如果您使用 Apache HTTP Server,则需要在公共文件夹中创建一个 .htaccess 文件,如下所示:
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
当您运行 npm run build 时,它将被复制到构建文件夹。
我修改了我的server.js并添加了.htaccess,问题解决了。