调用DELETE请求时出现HTTP 405错误:GET方法不支持的排查求助
问题:DataTable行删除功能触发405错误(GET请求不被支持)
我尝试为DataTable的每一行实现删除功能:通过触发Bootstrap模态框,向Spring控制器发送携带username参数的DELETE请求。但实际请求未路由到对应控制器,而是弹出错误:HTTP Status 405 - Request method 'GET' not supported。
相关代码:
JS代码:
$(document).ready(function () { $('#usersTable').DataTable({ "sAjaxSource": "users/list", "sAjaxDataProp": "", "aoColumns": [ {"mData": "username"}, {"mData": "firstName"}, {"mData": "lastName"}, {"mData": "status"}, {"mData": "role.roleName"}, { mRender: function (data, type, row) { var linkDel = "<a href=\"#\" onclick=\"fillDeleteFrm('username')\">Delete</a>"; linkDel = linkDel.replace("id", row.id); linkDel = linkDel.replace("name", row.name); return linkDel; } } ] }) }); function fillDeleteFrm(username) { $('#delete-username').val(username); $('#userDeleteModal').modal('toggle'); return false; }
Thymeleaf表单代码:
<div id="userDeleteModal"> <form id="systemUserForm" th:action="@{/userdelete}" th:method="delete"> <input type="hidden" id="delete-username" name="username" th:value="*{username}"> <button type="submit" class="btn btn-primary">Delete</button> </div> </form>
Spring控制器代码:
@ResponseBody @RequestMapping(value="/userdelete", method = RequestMethod.DELETE) public ModelAndView deleteEmployee(@RequestParam String username) { User user = userService.findUserByUserName(username); userService.deleteUser(user); return new ModelAndView("users"); }
错误原因分析
- HTML表单的方法限制:HTML原生表单只支持
GET和POST两种请求方法,你在Thymeleaf里写的th:method="delete",最终浏览器会默认发送GET请求,而你的控制器只接受DELETE方法,所以触发405错误。 - JS参数传递错误:你的删除链接生成代码里,
fillDeleteFrm('username')传递的是字符串'username',而不是当前行的实际username值;另外后面的replace("id", row.id)和replace("name", row.name)完全是无效操作,因为原字符串里根本没有id或name这两个子串。
具体修复步骤
1. 修复JS中的删除链接生成逻辑
把mRender里的代码改成正确传递当前行的username:
mRender: function (data, type, row) { // 直接把row.username传入fillDeleteFrm函数 return "<a href=\"#\" onclick=\"fillDeleteFrm('" + row.username + "'); return false;\">Delete</a>"; }
这样点击删除链接时,会把当前行的真实用户名传递给模态框的表单。
2. 调整Thymeleaf表单,模拟DELETE请求
因为HTML不支持直接发送DELETE,我们需要用POST请求配合Spring的HiddenHttpMethodFilter来模拟DELETE:
<div id="userDeleteModal" class="modal fade"> <div class="modal-dialog"> <div class="modal-content"> <form id="systemUserForm" th:action="@{/userdelete}" th:method="post"> <!-- 添加隐藏字段来告诉Spring这是DELETE请求 --> <input type="hidden" name="_method" value="delete"/> <input type="hidden" id="delete-username" name="username" th:value=""/> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> <button type="submit" class="btn btn-danger">Delete</button> </div> </form> </div> </div> </div>
注意:如果是Spring Boot项目,
HiddenHttpMethodFilter默认已经启用;如果是传统Spring MVC项目,需要在web.xml中手动配置这个过滤器。
3. 优化控制器(可选)
你的控制器用了@ResponseBody但返回了ModelAndView,这有点矛盾。如果是页面跳转,不需要@ResponseBody;如果是AJAX请求,应该返回JSON格式的结果。如果保持页面跳转的话,修改控制器:
@RequestMapping(value="/userdelete", method = RequestMethod.DELETE) public String deleteEmployee(@RequestParam String username) { User user = userService.findUserByUserName(username); userService.deleteUser(user); // 重定向到用户列表页面,避免表单重复提交 return "redirect:/users/list"; }
4. 可选:用AJAX发送DELETE请求(更优雅)
如果不想用表单提交,直接用AJAX发送DELETE请求,这样不需要模态框的表单,体验更好:
// 修改JS的mRender mRender: function (data, type, row) { return "<a href=\"#\" onclick=\"deleteUser('" + row.username + "'); return false;\">Delete</a>"; } // 添加删除函数 function deleteUser(username) { if(confirm("确定要删除用户 " + username + " 吗?")) { $.ajax({ url: "/userdelete", type: "DELETE", data: {username: username}, success: function() { // 重新加载DataTable数据 $('#usersTable').DataTable().ajax.reload(); alert("删除成功"); }, error: function() { alert("删除失败"); } }); } }
这种方式下,控制器可以返回JSON:
@ResponseBody @RequestMapping(value="/userdelete", method = RequestMethod.DELETE) public Map<String, Object> deleteEmployee(@RequestParam String username) { Map<String, Object> result = new HashMap<>(); try { User user = userService.findUserByUserName(username); userService.deleteUser(user); result.put("success", true); } catch (Exception e) { result.put("success", false); result.put("message", e.getMessage()); } return result; }
内容的提问来源于stack exchange,提问作者GeekySelene
相关产品推荐
相关产品推荐

