node.js - 如果用户更改浏览器,为什么我的 React 应用程序会显示 "Cannot GET/route"?

标签 node.js reactjs express npm react-router

我有一个使用 React-Router 和 Express 的 React 应用程序。我添加了一条新路由,它接受加密的私钥并允许用户通过电子邮件收件箱的链接自动登录。

路线如下:

<PublicRoute path="/loader/:user_key" component={Loader} />

{Loader} 是一个带有 componentWillMount() 函数的 React 组件,它解析 URL,获取“user_key”,对用户进行身份验证,创建 cookie,并将它们重定向到私有(private)“/home”路由。

该链接效果很好 - 只要用户之前已经从同一浏览器登录过该应用。但是,如果用户在一种浏览器(例如笔记本电脑)上创建帐户并从其他浏览器(例如手机)打开电子邮件链接,则浏览器将返回

"Cannot GET /loader/..."

你有什么建议吗?我做错了什么?

编辑

这里是server.js文件(包含关键表达逻辑)

const bodyParser = require("body-parser");
const expressValidator = require("express-validator");
const session = require("express-session");
const MongoStore = require("connect-mongodb-session")(session);
const mongoose = require("mongoose");
const passport = require("./config/passport/index.js");
const routes = require("./routes/index.js");
const express = require("express");
const app = express();
const http = require("http");
const path = require("path");
const PORT = process.env.PORT || 3001;
const MONGODB_URI =
  process.env.MONGODB_URI || "mongodb://localhost:27017/sonar";
mongoose.Promise = Promise;

//Parse application /x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

//Server instance
const server = http.createServer(app);

//Cronjobs
const cronjob = require("./cronjob.js");

// -------------------------- Sessions -----------------------------

//Initiate sessions
app.use(
  session({
    secret: "Secret",
    store: new MongoStore({ uri: MONGODB_URI, collection: "sessions" }),
    resave: true,
    saveUninitialized: true,
    cookie: {
      maxAge: 3*60*60*1000 // In milliseconds
    }
  })
);

//Initialize passport
app.use(passport.initialize());
app.use(passport.session()); // will call the deserializeUser

// --------------------- Backend Validation---------------------------

//This validates and sanitizes strings
app.use(
  expressValidator({
    errorFormatter: (param, msg, value) => {
      const namespace = param.split("."),
        root = namespace.shift(),
        formParam = root;

      while (namespace.length) {
        formParam += "[" + namespace.shift() + "]";
      }
      return {
        param: formParam,
        msg: msg,
        value: value
      };
    }
  })
);

// -------------------------- Routes -----------------------------

//Sets static assets path
app.use(express.static(path.join(__dirname, "/build")));

//Sets route to index
app.get("/", (req, res) => {
  // console.log("Is this firing? '/' ")
  res.sendFile(__dirname, "/index.html");
});

//Setting up routes in app
app.use(routes);

// -------------------------- MongoDB -----------------------------

// Connect to the Mongo DB
mongoose.connect(MONGODB_URI, { useNewUrlParser: true }, (err, db) => {
  if (err) {
    console.log("Unable to connect to the mongoDB server. Error:", err);
  } else {
    console.log("Connection established to", MONGODB_URI);
  }
});

const db = mongoose.connection;

// Show any mongoose errors
db.on("error", error => {
  console.log("Mongoose Error: ", error);
});

// Once logged in to the db through mongoose, log a success message
db.once("open", () => {
  console.log("Mongoose connection successful.");
});

// -------------------------- Listen -----------------------------

// Start the API server
app.listen(PORT, () => {
  console.log("App listening on PORT " + PORT);
});

编辑#2

一旦 server.js 返回 index.html 文件,问题似乎出在加载 React-Router 上。添加 index.html 文件以供引用:

 <!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">

    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-132577862-1"></script>

    <!-- Google Analytics -->
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());

        gtag('config', 'UA-132577862-1');
    </script>

    <!-- This deactivates browser navigation button: "Back" -->
    <script type="text/javascript" >
       function preventBack(){window.history.forward();}
        setTimeout("preventBack()", 0);
        window.onunload=function(){null};
    </script>

    <!-- Stripe checkout -->
    <!-- <script src="https://checkout.stripe.com/checkout.js"></script> -->

    <!-- React Script -->
    <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

    <!-- <meta name="theme-color" content="#000000"> -->
    <link rel="manifest" href="manifest.json">

    <link rel="shortcut icon" href="profilePicture/infinity_preloader.gif">

    <!-- Bootstrap CDN -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" id="bootstrap-css">

    <!-- jquery -->
    <script src="//code.jquery.com/jquery-1.11.1.min.js"></script>

    <!-- Moment.js (I don't think this is necessary - can delete?) -->
    <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script> -->

    <!-- This is the IE ES6 script work around -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=default,Array.prototype.includes"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.3.5/bluebird.min.js"></script>


    <!-- iPhone PWA icon -->
    <link rel="apple-touch-icon" sizes="180x180" href="profilePicture/dummy_profile_Pic2.png"> 

    <!-- iPhone splash screens -->
    <link rel="apple-touch-startup-image" href="profilePicture/dummy_profile_Pic2.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" />

    <link rel="apple-touch-startup-image" href="profilePicture/dummy_profile_Pic2.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" />

    <link rel="apple-touch-startup-image" href="profilePicture/dummy_profile_Pic2.png" media="(device-width: 621px) and (device-height: 1104px) and (-webkit-device-pixel-ratio: 3)" />

    <link rel="apple-touch-startup-image" href="profilePicture/dummy_profile_Pic2.png" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)" />

    <link rel="apple-touch-startup-image" href="profilePicture/dummy_profile_Pic2.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2)" />

    <link rel="apple-touch-startup-image" href="profilePicture/dummy_profile_Pic2.png" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2)" />

    <link rel="apple-touch-startup-image" href="profilePicture/dummy_profile_Pic2.png" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)" />

    <!-- Fonts -->
    <!-- <link href="https://fonts.googleapis.com/css?family=Nunito+Sans" rel="stylesheet"> -->
    <link href="https://fonts.googleapis.com/css?family=Inconsolata|Lato|Nunito|Montserrat" rel="stylesheet">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

    <title>Cratic | The Culture Builder</title>
  </head>
  <body>
    <div id="root" ></div>
  </body>
</html>

最佳答案

在您的server.jsexpress文件中添加一个通配符路由,捕获任何可能不匹配的路由并与index.html文件一起返回,这允许react-router在前端接管和路由:

...

// -------------------------- Routes -----------------------------

//Sets static assets path
app.use(express.static(path.join(__dirname, "/build")));

//Sets route to index
app.get("/", (req, res) => {
  // console.log("Is this firing? '/' ")
  res.sendFile(__dirname, "/index.html");
});

//Setting up routes in app
app.use(routes);

// WILDCARD ROUTE HANDLER
app.get("*", (req, res) => {
  res.sendFile(__dirname, "/index.html");
};

...


这是完整的 server.js 文件:

const bodyParser = require("body-parser");
const expressValidator = require("express-validator");
const session = require("express-session");
const MongoStore = require("connect-mongodb-session")(session);
const mongoose = require("mongoose");
const passport = require("./config/passport/index.js");
const routes = require("./routes/index.js");
const express = require("express");
const app = express();
const http = require("http");
const path = require("path");
const PORT = process.env.PORT || 3001;
const MONGODB_URI =
  process.env.MONGODB_URI || "mongodb://localhost:27017/sonar";
mongoose.Promise = Promise;

//Parse application /x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

//Server instance
const server = http.createServer(app);

//Cronjobs
const cronjob = require("./cronjob.js");

// -------------------------- Sessions -----------------------------

//Initiate sessions
app.use(
  session({
    secret: "Secret",
    store: new MongoStore({ uri: MONGODB_URI, collection: "sessions" }),
    resave: true,
    saveUninitialized: true,
    cookie: {
      maxAge: 3*60*60*1000 // In milliseconds
    }
  })
);

//Initialize passport
app.use(passport.initialize());
app.use(passport.session()); // will call the deserializeUser

// --------------------- Backend Validation---------------------------

//This validates and sanitizes strings
app.use(
  expressValidator({
    errorFormatter: (param, msg, value) => {
      const namespace = param.split("."),
        root = namespace.shift(),
        formParam = root;

      while (namespace.length) {
        formParam += "[" + namespace.shift() + "]";
      }
      return {
        param: formParam,
        msg: msg,
        value: value
      };
    }
  })
);

// -------------------------- Routes -----------------------------

//Sets static assets path
app.use(express.static(path.join(__dirname, "/build")));

//Sets route to index
app.get("/", (req, res) => {
  // console.log("Is this firing? '/' ")
  res.sendFile(__dirname, "/index.html");
});

//Setting up routes in app
app.use(routes);

// WILDCARD ROUTE HANDLER
app.get("*", (req, res) => {
  res.sendFile(__dirname, "index.html");
}

// -------------------------- MongoDB -----------------------------

// Connect to the Mongo DB
mongoose.connect(MONGODB_URI, { useNewUrlParser: true }, (err, db) => {
  if (err) {
    console.log("Unable to connect to the mongoDB server. Error:", err);
  } else {
    console.log("Connection established to", MONGODB_URI);
  }
});

const db = mongoose.connection;

// Show any mongoose errors
db.on("error", error => {
  console.log("Mongoose Error: ", error);
});

// Once logged in to the db through mongoose, log a success message
db.once("open", () => {
  console.log("Mongoose connection successful.");
});

// -------------------------- Listen -----------------------------

// Start the API server
app.listen(PORT, () => {
  console.log("App listening on PORT " + PORT);
});

如果您有错误或者这不能解决问题,请告诉我!

关于node.js - 如果用户更改浏览器,为什么我的 React 应用程序会显示 "Cannot GET/route"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59216683/

相关文章:

javascript - 如何使用云函数、Node.js 和 Javascript 对 Firebase 实时数据库进行排序和筛选 'High Score' 排行榜

javascript - 咕噜.js : Loading task causes TypeError: object is not a function

javascript - 无法在 Express JS 中设置单独的路由文件

regex - Restify 中的通配符路由

node.js - 如何动态刷新 EJS 标签中的 JSON 数据

javascript - Firebase 谷歌云函数 : createReadStream results in empty file

javascript - 将基于 cheerio 的搜索循环添加到 node-simplecrawler

javascript - React.js 变量

javascript - ReactJS:无法通过对象数组进行映射

javascript - react-dom 爆出 webpack 包的大小