Express登录中间件异常:登出后无法渲染登录页面
问题:登出后登录页面无法渲染的排查与解决
我是一名Web开发新手,开发了一个登录页面(将用户输入的邮箱保存为Cookie)和账户页面(点击登出按钮删除该Cookie),并编写了中间件,试图在Cookie被删除(用户登出)时将用户重定向到登录页面。Cookie存在时一切功能正常,但点击登出按钮后,登录页面无法渲染。
相关代码
登录路由代码
const fs = require('fs'); const path = require('path'); const { v4 } = require('uuid'); const express = require("express"); const cookieParser = require('cookie-parser'); const { containsObject, getUsers } = require('../Auth/auth.cjs'); const {userExists} = require('./signin.cjs') const router = express.Router(); router.get('/', (req, res) => { const {cookies} = req; if(cookies['email']){ res.redirect('/main'); } else{ res.render('SignIn/signin'); } }) router.post('/', async (req, res) => { const user = { email:req.body.email, password:req.body.password, } const result = await userExists(user); if(result){ res.cookie('email', req.body.email); res.redirect('/main'); } else{ res.render('SignIn/signin', user) } }) module.exports = router;
登出按钮表单
<form method="post"> <input type="submit" value="Log out"/> </form>
登出路由代码
const fs = require('fs'); const path = require('path'); const { v4 } = require('uuid'); const express = require('express'); const { route } = require('../SignIn/signin'); const { compile } = require('ejs'); const {getUser, getPostsFromUser} = require('./account.cjs') const router = express.Router(); router.get("/", async (req, res) => { const {cookies} = req; const email = cookies['email']; const userResponse = await getUser(email); const user = { username:userResponse['username'], email:userResponse['email'], } console.log(await getPostsFromUser(user)); res.render('Account/account', user); }) router.post('/', (req, res) => { res.cookie('email', '', {expires: new Date(0)}); res.clearCookie("email"); res.redirect('/sign') }) module.exports = router;
主文件代码
const { localsName } = require("ejs"); const express = require("express"); const app = express(); const cookieParser = require('cookie-parser'); const users = [] let loggedIn = false app.set('view engine', 'ejs'); app.use(cookieParser()); app.use(express.static('public')); app.use(express.urlencoded({extended:true})) app.use((req, res, next) => { const {cookies} = req; console.log(cookies['email']) if(cookies['email'] == undefined){ return res.redirect('/sign'); } else{ next(); } }) app.get('/', (req, res) =>{ res.redirect('/sign') }) const signRouter = require('./views/SignIn/signin.js'); app.use('/sign', signRouter); const authRouter = require('./views/Auth/auth.js'); app.use('/auth', authRouter); const mainRouter = require('./views/Main/main.js'); app.use('/main', mainRouter); const addPostRouter = require('./views/Add_post/add_post.js'); app.use('/add-post', addPostRouter); const accountRouter = require('./views/Account/account.js'); app.use('/account', accountRouter); app.listen(3000)
问题原因
核心问题是全局中间件的位置错误:你在主文件中定义的全局中间件会拦截所有请求,包括登录路由(/sign)的请求。当用户登出后,Cookie被清除,此时访问/sign时,全局中间件检测到cookies['email']不存在,会再次重定向到/sign,形成无限重定向循环,导致浏览器无法正常渲染页面。
另外,登出路由中同时使用res.cookie('email', '', {expires: new Date(0)})和res.clearCookie("email")属于重复操作,没必要同时执行。
解决方案
1. 调整全局中间件的作用范围
将全局中间件移到登录路由之后,只对需要登录验证的路由(如/main、/account等)生效,避免拦截登录页面的请求:
修改后的主文件代码:
const { localsName } = require("ejs"); const express = require("express"); const app = express(); const cookieParser = require('cookie-parser'); const users = [] let loggedIn = false app.set('view engine', 'ejs'); app.use(cookieParser()); app.use(express.static('public')); app.use(express.urlencoded({extended:true})) // 先挂载登录路由,避免被中间件拦截 app.get('/', (req, res) =>{ res.redirect('/sign') }) const signRouter = require('./views/SignIn/signin.js'); app.use('/sign', signRouter); const authRouter = require('./views/Auth/auth.js'); app.use('/auth', authRouter); // 定义登录验证中间件,只对后续路由生效 app.use((req, res, next) => { const {cookies} = req; if(cookies['email'] == undefined){ return res.redirect('/sign'); } next(); }) // 挂载需要登录验证的路由 const mainRouter = require('./views/Main/main.js'); app.use('/main', mainRouter); const addPostRouter = require('./views/Add_post/add_post.js'); app.use('/add-post', addPostRouter); const accountRouter = require('./views/Account/account.js'); app.use('/account', accountRouter); app.listen(3000)
2. 优化登出逻辑
删除重复的Cookie设置代码,只保留res.clearCookie("email")即可:
修改后的登出路由post方法:
router.post('/', (req, res) => { res.clearCookie("email"); res.redirect('/sign') })
原理说明
调整中间件位置后,登录路由(/sign)不会被登录验证中间件拦截,用户登出后重定向到/sign时,能正常进入登录路由的get方法,渲染登录页面。而需要登录的路由(如/main、/account)会先经过中间件验证,未登录时自动重定向到登录页,逻辑正常。
内容的提问来源于stack exchange,提问作者will
相关产品推荐
相关产品推荐

