快速路线在本地有效,但不适用于生产

时间:2020-09-29 09:38:09

标签: node.js reactjs apache express static

我们目前正在通过apache2反向代理部署由nodejs / express服务器提供的静态React应用服务。该应用程序的索引工作正常,但如果页面不存在,我会尝试重定向,这在localhost上有效,但在远程服务器上则无效。如果我转到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(frontend),它是在后端文件夹中构建并设置的

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)中,那么我将无法查询诸如/的直接URL: id cuz我也得到404

1 个答案:

答案 0 :(得分:0)

像往常一样,我应该更好地进行RTFD。 https://create-react-app.dev/docs/deployment/#serving-apps-with-client-side-routing

If you use routers that use the HTML5 pushState history API under the hood (for example, React Router with browserHistory), many static file servers will fail. For example, if you used React Router with a route for /todos/42, the development server will respond to localhost:3000/todos/42 properly, but an Express serving a production build as above will not.

This is because when there is a fresh page load for a /todos/42, the server looks for the file build/todos/42 and does not find it. The server needs to be configured to respond to a request to /todos/42 by serving index.html. For example, we can amend our Express example above to serve index.html for any unknown paths:

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'));
 });

If you’re using Apache HTTP Server, you need to create a .htaccess file in the public folder that looks like this:

Options -MultiViews
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.html [QSA,L]
    

It will get copied to the build folder when you run npm run build.

我修改了server.js并添加了.htaccess,问题解决了。