使用ExpressJS和CSRF时无法发起POST请求的问题排查
排查"Cannot POST /process"错误的关键问题
让我帮你梳理下代码里的两个核心问题,这就是导致错误的根源:
1. 表单提交路径不匹配
你的routesAPI路由器在index.js里是挂载在/api前缀下的:
app.use("/api", routesAPI);
而routes-api.js里的POST路由是/process,所以这个接口的实际完整路径是/api/process,但你表单里写的action是/process,浏览器直接请求根路径下的/process,但这个路由根本不存在,所以触发了"Cannot POST /process"的错误。
解决办法:
修改send.html里的表单action:
<form action="/api/process" method="POST">
2. 静态文件无法渲染模板变量
你用res.sendFile()发送send.html,但这个方法只是把文件原封不动返回给浏览器,不会解析里面的{{csrfToken}}模板变量。所以表单里的_csrf字段值其实是字符串{{csrfToken}},不是真实的CSRF令牌——就算路径改对了,后续也会触发CSRF验证失败。
解决办法:
有两种方式处理这个问题:
方式一:直接生成HTML字符串返回
如果不想用模板引擎,可以在路由里直接拼接HTML,把CSRF令牌嵌入进去:
router.get("/", csrfProtection, (req, res) => { console.log("crsf: " + req.csrfToken()); const formHtml = ` <form action="/api/process" method="POST"> <input type="text" name="_csrf" value="${req.csrfToken()}"> Favorite color: <input type="text" name="favoriteColor"> <button type="submit">Submit</button> </form> `; res.send(formHtml); });
方式二:使用模板引擎(更推荐)
如果后续页面复杂,建议用模板引擎来渲染页面,比如EJS:
- 先安装EJS依赖:
npm install ejs
- 在
index.js里配置模板引擎:
const path = require('path'); // ... 其他代码 app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views')); // 新建一个views文件夹存放模板文件
- 把
send.html改名为send.ejs,放到views文件夹里,内容保持不变; - 修改
routes-api.js里的GET路由,用res.render()渲染模板:
router.get("/", csrfProtection, (req, res) => { console.log("crsf: " + req.csrfToken()); res.render('send', { csrfToken: req.csrfToken() }); });
做完这两步修改后,重新启动服务器,表单就能正确提交到/api/process,并且CSRF令牌也能正确传递了。
内容的提问来源于stack exchange,提问作者José Carlos
相关产品推荐
相关产品推荐

