ExpressJS:拆分路由后CSRF配置错误排查——无法生成CSRF令牌
问题分析与修复方案
你遇到的问题核心是在路由文件里错误创建了新的Express实例,且中间件挂载到了这个无关实例上,导致CSRF模块依赖的Cookie解析逻辑没有加入主应用的请求处理链中,最终令牌生成/验证失效。下面具体拆解问题和修复步骤:
核心错误点
- 重复创建Express实例:在
routes-api.js中你声明了const app = express();,但这个新实例和index.js里的主应用完全独立,你在这个新app上挂载的cookieParser()根本不会作用到主应用的请求上,而CSRF模块依赖Cookie解析来生成和校验令牌,自然无法正常工作。 - 中间件挂载位置错误:你把
cookieParser()挂载到了新的app实例上,而非当前路由的中间件链或主应用的全局中间件链中,导致CSRF无法获取到必要的Cookie上下文。
修复后的代码
第一步:修正routes-api.js
删除多余的Express实例,将中间件挂载到当前路由上,同时去掉重复的bodyParser引入(主应用已全局配置):
var cookieParser = require('cookie-parser'); var csrf = require('csurf'); var express = require('express'); const path = require("path"); const router = express.Router(); // 配置路由级中间件 var csrfProtection = csrf({ cookie: true }); // 将cookieParser挂载到当前router,确保在csrfProtection之前执行 router.use(cookieParser()); router.get("/", csrfProtection, (req, res) => { console.log("csrf: " + req.csrfToken()); // 注意:sendFile不支持模板变量传递,需替换为模板渲染或手动替换内容 const fs = require('fs'); const filePath = path.join(__dirname + '/send.html'); fs.readFile(filePath, 'utf8', (err, content) => { if (err) return res.status(500).send('加载HTML文件失败'); // 假设send.html中有占位符<input type="hidden" name="_csrf" value="{{csrfToken}}"> const updatedContent = content.replace('{{csrfToken}}', req.csrfToken()); res.send(updatedContent); }); }); module.exports = router;
第二步:优化index.js(可选但更规范)
将cookieParser移到主应用的全局中间件链中,让所有路由共享该中间件,避免在路由文件中重复配置:
//Creación de un servidor con express const express = require("express"); const app = express(); //Inicializamos express //Accedemos a otros módulos const morgan = require("morgan"); const bodyParser = require("body-parser"); const jwt = require("jsonwebtoken"); const cookieParser = require('cookie-parser'); // 新增引入cookieParser //Accedemos a propiedades de configuración const config = require("./config"); //Rutas const routes = require("./routes"); const routesAPI = require("./routes-api"); //Settings app.set("app-name", config.server); app.set("port", config.port); app.set("super-secret", config.secret); //Middlewares // use body parser so we can get info from POST and/or URL parameters app.use(bodyParser.urlencoded({extended: false})); app.use(bodyParser.json()); app.use(morgan("dev")); //Log request to the console app.use(cookieParser()); // 全局配置Cookie解析中间件 app.use((req, res, next) => { console.log("Pasamos por la segunda función!!!"); next(); }); //Routing app.use("/api", routesAPI); app.use(routes); //Server app.listen(app.get("port"), () => { console.log("Servidor " + app.get("app-name") + " escuchando!!!"); });
如果做了这一步,routes-api.js里的router.use(cookieParser())就可以删除了。
额外说明
你原本用res.sendFile传递csrfToken参数是无效的,因为sendFile仅用于发送静态文件,不支持模板变量替换。上面的修复代码中用了手动读取文件并替换占位符的方式,你也可以改用EJS、Pug等模板引擎,通过res.render来渲染页面并传入令牌。
内容的提问来源于stack exchange,提问作者José Carlos
相关产品推荐
相关产品推荐

