【发布时间】:2020-03-31 15:44:51
【问题描述】:
我有一个使用 React-Router 和 Express 的 React 应用程序。我添加了一条新路由,它接受加密的私钥并允许用户通过指向其电子邮件收件箱的链接自动登录。
路线如下:
<PublicRoute path="/loader/:user_key" component={Loader} />
{Loader} 是一个带有 componentWillMount() 函数的 React 组件,它解析 URL,获取“user_key”,验证用户,创建 cookie,并将它们重定向到私有“/home”路由。
该链接非常有效——只要用户之前已经从相同浏览器登录到应用程序。但是,如果用户在一个浏览器(例如笔记本电脑)上创建了他们的帐户并从另一个浏览器(例如手机)打开电子邮件链接,浏览器会返回
“无法获取 /loader/...”
你有什么建议吗?我做错了什么?
编辑
这里是 server.js 文件(包含 key express 逻辑)
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
问题似乎在于加载 React-Router,一旦 server.js 返回 index.html 文件。添加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>
【问题讨论】:
-
这里有几个问题,您的应用程序是否使用任何形式的
local storage或其他 PWA 功能?而且,您可以发布您的主要express应用程序文件吗?将所有请求重定向到index.html非常重要,这样 react-router 可以接管并呈现正确的组件。 -
更具体地说,重要的是 react-router 和 express 一起正确运行,您可以通过 express 将 api 请求从 react 引导到处理程序,但将请求(用于 react-router)路由到索引.html - 这允许反应路由器接管并在前端显示正确的内容。
-
@MikeAbeln - 我添加了
server.js文件。我使用local storage处理带有cookie 的私有路由。所有授权都使用passport-local策略完成。但是,“cannot GET/”错误似乎发生在授权开始之前。
标签: node.js reactjs express npm react-router