很奇葩的Nodejs跳转问题

很奇葩的Nodejs跳转问题

app.del(’/:id’,function(req,res){
User.findById(req.params.id,function(err,doc){
if(!doc){
return next(new NotFound(‘document is not found’))
}
doc.remove(function(){
res.redirect(’/listuser’);
});
})
});
<% for(var i=0; i<doc.length; i++) { %>
<li>
<%= doc[i].id %>
<%= doc[i].username %>
<%= doc[i].password %>
<form method=‘post’ ,action=’/<%= doc[i].id %>’>
<input type=“submit” value=“del” />
</form>
</li>
<% } %>

Cannot POST /listuser ejs 为啥啊? app.post也不行。。。


5 回复

很奇葩的Nodejs跳转问题

问题描述

在使用Node.js和EJS模板引擎时,我遇到了一个很奇怪的问题。当我在前端页面点击删除按钮后,虽然成功删除了数据库中的记录,但页面却无法正确跳转到用户列表页面(/listuser)。相反,页面返回了一个 Cannot POST /listuser 的错误。

示例代码

首先来看一下后端的删除逻辑:

// app.js
const express = require('express');
const User = require('./models/User'); // 假设你有一个User模型
const app = express();

app.set('view engine', 'ejs');

app.del('/:id', function(req, res) {
    User.findById(req.params.id, function(err, doc) {
        if (!doc) {
            return next(new NotFound('document is not found'));
        }
        doc.remove(function() {
            res.redirect('/listuser');
        });
    });
});

app.get('/listuser', function(req, res) {
    User.find({}, function(err, docs) {
        if (err) throw err;
        res.render('listuser', { doc: docs });
    });
});

app.listen(3000);

然后是前端的HTML代码,用于展示用户列表并提供删除功能:

<!-- views/listuser.ejs -->
<ul>
<% for(var i=0; i<doc.length; i++) { %>
    <li>
        <%= doc[i].id %> - <%= doc[i].username %> - <%= doc[i].password %>
        <form method='post' action='/<%= doc[i].id %>'>
            <input type="submit" value="Delete" />
        </form>
    </li>
<% } %>
</ul>

问题分析

从上述代码可以看出,删除操作通过POST请求发送到服务器,而服务器实际处理的是DELETE请求。因此,当你提交表单时,客户端尝试向 /listuser 发送POST请求,但实际上并没有这样的路由来处理这个请求,所以返回了 Cannot POST /listuser 错误。

解决方案

  1. 修改前端表单的提交方式:将表单的提交方法改为DELETE,而不是POST。这可以通过在表单中添加一个隐藏字段来实现。
<form method='post' action='/<%= doc[i].id %>'>
    <input type="hidden" name="_method" value="delete">
    <input type="submit" value="Delete" />
</form>
  1. 更新后端路由处理:使用中间件来处理 _method 参数,并根据其值更改HTTP方法。
// app.js
const methodOverride = require('method-override');

app.use(methodOverride('_method'));

app.delete('/:id', function(req, res) {
    User.findById(req.params.id, function(err, doc) {
        if (!doc) {
            return next(new NotFound('document is not found'));
        }
        doc.remove(function() {
            res.redirect('/listuser');
        });
    });
});

通过以上修改,前端表单将正确地发送DELETE请求到后端,后端也会正确处理该请求,并重定向到用户列表页面。


有启用method-override模块吗? 如果没有, 启用该模块,再加个 <input type="hidden" value="DELETE" name="_method">

可以删除了 不过没有执行跳转 显示Moved Temporarily. Redirecting to /listuser

<form method=‘post’ ,action=’/<%= doc[i].id%>/userdel’> app.del(’/:id/userdel’,function(req,res){ 这样则显示Cannot DELETE /listuser

根据你的描述,问题出在HTML表单提交的方式。你在EJS模板中使用了<form>标签,并且其method属性设置为POST,而action属性则指向了一个动态路径(如/123),这会导致浏览器尝试通过POST方法向/123发送请求,而不是/listuser

如果你想实现删除功能并重定向到用户列表页面,可以考虑以下方案:

  1. 使用DELETE方法模拟删除操作,可以通过隐藏字段或者改变formmethodDELETE来实现。
  2. 修改服务器端代码,处理正确的HTTP方法。

示例代码

修改服务器端代码

const express = require('express');
const User = require('./models/User'); // 假设User模型已定义
const app = express();

app.delete('/:id', function (req, res, next) {
  User.findById(req.params.id, function (err, doc) {
    if (!doc) {
      return next(new NotFound('document is not found'));
    }
    doc.remove(function () {
      res.redirect('/listuser');
    });
  });
});

// 添加对DELETE请求的支持
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.post('/:id/delete', function (req, res) {
  req._parsedUrl = { pathname: '/delete' };
  const id = req.params.id;
  app._router.handle(req, res, function () {});
});

app.listen(3000, () => console.log('Server started on port 3000'));

修改客户端EJS模板

<% for (var i = 0; i < doc.length; i++) { %>
<li>
  <%= doc[i].id %>
  <%= doc[i].username %>
  <%= doc[i].password %>
  <form method="post" action="/<%= doc[i].id %>/delete">
    <input type="hidden" name="_method" value="DELETE" />
    <input type="submit" value="del" />
  </form>
</li>
<% } %>

在这个例子中,我们通过添加一个隐藏的_method字段,并将其值设置为DELETE,模拟了DELETE请求。然后,在服务器端,我们通过检查请求体中的_method字段来决定如何处理请求。

这样,当用户点击“del”按钮时,会发送一个POST请求到正确的路径,服务器端则会处理该请求并进行相应的删除操作。

回到顶部