Express.js中csrfProtection未定义问题求助及Router解决记录
问题描述
作为Express/Node.js新手,我尝试在index.js中引入app.js和myCustomCsrf.js,但运行时抛出错误:ReferenceError: csrfProtection is not defined。以下是三个文件的原始代码:
index.js
const app = require("./app.js"); const PORT = 5000 app.listen(PORT) require("./myCustomCsrf.js") app.get('/*', function(req, res) { res.sendFile(path.join(__dirname, '/build/index.html'), function(err) { if (err) { res.status(500).send(err) } }) })
app.js
const express = require('express') const path = require('path') const mysql = require('mysql'); const crypto = require('crypto'); const cookieParser = require('cookie-parser') const csrf = require('csurf') const bodyParser = require('body-parser') const cors = require('cors') const session = require('express-session'); const { generateKey } = require('crypto'); // setup route middlewares const csrfProtection = csrf({ cookie: true }) const parseForm = bodyParser.urlencoded({ extended: false }) // create express app const app = express() const corsOptions = { origin: "http://localhost:3000", credentials: true, } app.use(cors(corsOptions)); // setup session app.use(session( { key: "guestSession", secret: "yourSecretHere", resave: false, saveUninitialized: false, cookie: { maxAge: 1000 * 60 * 60 * 24 } } )) // parse cookies // we need this because "cookie" is true in csrfProtection app.use(cookieParser()) app.use(express.static(path.join(__dirname + "/public"))) app.use(express.json()) module.exports = app
myCustomCsrf.js
const app = require("../app"); // set his csrf value in useState in frontend (react) app.get("/api/checkguest", csrfProtection, (req, res) => { res.send({value: req.csrfToken() }) });
错误原因
- 作用域问题:
csrfProtection是app.js内部定义的局部变量,myCustomCsrf.js无法直接访问该变量,导致引用错误。 - 路径错误:
myCustomCsrf.js中使用require("../app"),若myCustomCsrf.js与app.js在同一目录下,正确路径应为require("./app"),否则会找不到app.js文件。 - index.js遗漏依赖:
index.js中使用了path模块但未引入,会导致后续res.sendFile执行报错。
正确的文件组织与引入方式
方法1:导出并共享csrfProtection
通过修改app.js导出csrfProtection,让myCustomCsrf.js可以直接引入使用:
修改app.js
在文件末尾修改导出语句,同时导出app和csrfProtection:
module.exports = { app, csrfProtection };
修改myCustomCsrf.js
修正路径并引入所需变量:
const { app, csrfProtection } = require("./app"); app.get("/api/checkguest", csrfProtection, (req, res) => { res.send({value: req.csrfToken() }) });
修改index.js
调整引入方式并补充path模块:
const { app } = require("./app.js"); const path = require('path'); const PORT = 5000; // 确保先加载路由再启动服务 require("./myCustomCsrf.js"); app.get('/*', function(req, res) { res.sendFile(path.join(__dirname, '/build/index.html'), function(err) { if (err) { res.status(500).send(err) } }) }); app.listen(PORT);
方法2:使用Express Router(推荐)
这是更符合模块化开发的方案,通过Router解耦路由与app实例,避免直接依赖全局变量:
修改myCustomCsrf.js
创建Router实例并定义路由,可自行初始化csrfProtection或从app.js引入:
const express = require('express'); const csrf = require('csurf'); const router = express.Router(); // 初始化csrf保护中间件(也可从app.js导出引入) const csrfProtection = csrf({ cookie: true }); router.get("/api/checkguest", csrfProtection, (req, res) => { res.send({value: req.csrfToken() }) }); module.exports = router;
修改app.js
在合适位置(中间件挂载完成后)引入并挂载Router:
// 在app.js末尾、module.exports之前添加 const csrfRouter = require('./myCustomCsrf'); app.use(csrfRouter); module.exports = app;
修改index.js
无需单独引入myCustomCsrf.js,只需确保app.js已正确挂载路由,同时补充path模块:
const app = require("./app.js"); const path = require('path'); const PORT = 5000; app.get('/*', function(req, res) { res.sendFile(path.join(__dirname, '/build/index.html'), function(err) { if (err) { res.status(500).send(err) } }) }); app.listen(PORT);
方法3:通过函数参数传递依赖
将app和csrfProtection作为参数传递给myCustomCsrf.js,适合简单场景:
修改myCustomCsrf.js
改为导出一个函数,接收依赖参数:
module.exports = function(app, csrfProtection) { app.get("/api/checkguest", csrfProtection, (req, res) => { res.send({value: req.csrfToken() }) }); };
修改index.js
调整引入逻辑,传递所需参数:
const { app, csrfProtection } = require("./app.js"); const path = require('path'); const PORT = 5000; // 传递app和csrfProtection给路由模块 require("./myCustomCsrf.js")(app, csrfProtection); app.get('/*', function(req, res) { res.sendFile(path.join(__dirname, '/build/index.html'), function(err) { if (err) { res.status(500).send(err) } }) }); app.listen(PORT);
额外注意事项
- 中间件顺序:确保
cookieParser、session等中间件在csrfProtection之前挂载,否则无法生成有效的CSRF Token。 - 启动顺序:建议先加载所有路由和中间件,再调用
app.listen()启动服务,避免路由未注册完成。
内容的提问来源于stack exchange,提问作者Galbert
相关产品推荐
相关产品推荐

