使用Node、Express、Mongoose时,DELETE删除功能失效但GET可用的原因与解决
问题
我正在开发一个CRUD项目,使用MongoDB、Express和Node.js实现根据ID删除条目。原删除功能用GET路由可以正常工作:
router.get('/delete/:id', async (req, res) => { try { const topic = await Topic.findById(req.params.id) await Topic.remove({ _id: req.params.id }) res.redirect('/dashboard') } catch (error) { console.log(error) } })
对应的EJS代码:
<div class="modifyTopic"> <a href="/edit/<% topic._id %>"><i class="fas fa-edit fa-2x"></i></a> <a href="/delete/<%= topic._id %>"><i class="fas fa-trash fa-2x"></i></a> </div>
但把路由改成DELETE方法后:
router.delete('/delete/:id', async (req, res) => { try { const topic = await Topic.findById(req.params.id) await Topic.remove({ _id: req.params.id }) res.redirect('/dashboard') } catch (error) { console.log(error) } })
功能失效,浏览器提示Cannot GET /delete/62def4aae6c2c1914cfa145fer3。请问:
- 为何会出现这种情况?
- 是否应该使用DELETE方法?
- 如何让删除功能通过DELETE方法正常工作?
解答
一、为什么改成DELETE路由后失效?
浏览器里的<a>标签默认会发送GET请求,但你把路由改成了DELETE方法,此时服务器上没有匹配该路径的GET路由,自然会返回Cannot GET错误。核心原因是请求方法和路由定义的方法不匹配。
二、是否应该使用DELETE方法?
必须用。按照RESTful API规范,删除资源的操作就该对应DELETE方法,用GET删资源存在诸多问题:
- 不符合HTTP语义,GET本来是用来获取资源的;
- 容易被爬虫、浏览器预加载误触发,导致数据意外删除;
- 无法通过HTTP方法区分操作类型,不利于接口的维护和扩展。
三、实现DELETE方法删除的两种方案
方案1:用表单+method-override中间件(传统后端渲染方案)
HTML表单默认只支持GET和POST,所以需要借助method-override中间件把POST请求转换成DELETE:
- 安装并配置中间件
先安装依赖:
在Express入口文件(比如npm install method-overrideapp.js)里添加配置:const methodOverride = require('method-override'); // 用表单字段指定真实请求方法 app.use(methodOverride('_method')); - 修改EJS代码,把a标签换成表单
把删除按钮的a标签改成表单提交:<div class="modifyTopic"> <a href="/edit/<%= topic._id %>"><i class="fas fa-edit fa-2x"></i></a> <form action="/delete/<%= topic._id %>" method="POST" style="display: inline; margin: 0;"> <input type="hidden" name="_method" value="DELETE"> <button type="submit" style="border: none; background: transparent; padding: 0; cursor: pointer;"> <i class="fas fa-trash fa-2x"></i> </button> </form> </div> - 优化路由代码
Topic.remove()已被废弃,推荐用更简洁的findByIdAndDelete:router.delete('/delete/:id', async (req, res) => { try { await Topic.findByIdAndDelete(req.params.id); res.redirect('/dashboard'); } catch (error) { console.error(error); res.status(500).send('删除失败'); } })
方案2:用AJAX发送DELETE请求(动态交互场景)
保留a标签,通过JavaScript阻止默认跳转,用fetch发送DELETE请求:
- 修改EJS代码,给删除按钮加类标识
<div class="modifyTopic"> <a href="/edit/<%= topic._id %>"><i class="fas fa-edit fa-2x"></i></a> <a href="/delete/<%= topic._id %>" class="delete-btn"><i class="fas fa-trash fa-2x"></i></a> </div> - 添加前端JS逻辑
在页面底部或独立JS文件中添加:document.querySelectorAll('.delete-btn').forEach(btn => { btn.addEventListener('click', async (e) => { e.preventDefault(); // 阻止默认GET跳转 const deleteUrl = e.currentTarget.href; if (confirm('确定要删除这条记录吗?')) { try { const response = await fetch(deleteUrl, { method: 'DELETE' }); if (response.ok) { window.location.href = '/dashboard'; // 删除成功后跳转 } else { alert('删除失败,请重试'); } } catch (err) { console.error(err); alert('删除请求出错'); } } }); }); - 路由代码保持不变(同样建议用
findByIdAndDelete优化)
内容的提问来源于stack exchange,提问作者aquile hollins
相关产品推荐
相关产品推荐

