Asp.Net Core 6调用删除模态框确认动作时出现405错误
问题描述
我正在开发首个Asp.Net Core应用,对模态框、Razor页面和路由映射完全陌生,JavaScript也已生疏。尝试制作一个可用于任意对象(测试对象为Employee类型)的通用删除模态框,模态框能正常显示,但点击调用DeletePOST方法时出现405错误,请求URL为https://localhost:44313/Employee/DeletePOST/1(选中ID为1的员工时),控制台出现警告:(index):6789 crbug/1173575, non-JS module files deprecated.(anonymous) @ (index):6789。
问题分析
405 Method Not Allowed错误的直接原因是:通过window.location.href = pathToDelete发起的是GET请求,但后端DeletePOST方法标记了[HttpPost]属性,仅接受POST请求,因此服务器拒绝该请求。
另外还有两处细节问题:
- 视图中循环生成的删除按钮都使用了相同的
id="#delete",违反HTML中id必须唯一的规则 - JavaScript中获取
data-id时,若点击的是按钮内的<i>图标,e.target会指向图标元素而非按钮,导致无法正确获取data-id
解决方案
1. 修正视图代码(View.Employee.Index)
删除重复的id="#delete",并修正data-url的生成方式:
<tbody> @foreach (var employee in Model) { <tr id="row_@employee.Id"> <td>@employee.Name</td> <td>@employee.Phone</td> <td>@employee.Email</td> <td>@employee.Address</td> <td>@employee.Role</td> <td>@employee.Availability</td> <td class="w-100 btn-group" role="group"> <a asp-controller="Employee" asp-action="Edit" asp-route-id="@employee.Id" class="btn btn-primary mx-2"> <i class="bi bi-pencil-square"></i> Edit</a> <!--delete modal confirmation button--> <a class="btn btn-danger delete" data-id="@employee.Id" data-url="@Url.Action("DeletePOST", "Employee")" data-body-message="Are you sure you want to delete this employee?"> <i class="bi bi-trash"></i> Delete</a> </td> </tr> } </tbody>
2. 修改JavaScript提交逻辑(wwwroot.js.delete.js)
替换window.location.href的跳转方式,改为动态创建表单提交POST请求,同时包含防伪令牌:
$((function () { var pathToDelete; var id; $('body').append(` <div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-bs-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span> </button> <h4 class="modal-title" id="myModalLabel">Warning</h4> </div> <div class="modal-body delete-modal-body"> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal" id="cancel-delete">Cancel</button> <button type="button" class="btn btn-danger" id="confirm-delete">Delete</button> </div> </div> </div> </div>`); //Delete Action $(".delete").on('click', (e) => { e.preventDefault(); // 用currentTarget确保获取的是按钮本身,而非内部图标 const $btn = $(e.currentTarget); id = $btn.data('id'); pathToDelete = $btn.data('url'); var bodyMessage = $btn.data('body-message'); // 拼接id到请求路径 pathToDelete = `${pathToDelete}/${id}`; $(".delete-modal-body").text(bodyMessage); $("#deleteModal").modal('show'); }); $("#confirm-delete").on('click', () => { // 动态创建表单提交POST请求 const form = $('<form>', { method: 'POST', action: pathToDelete }); // 添加防伪令牌(Asp.Net Core默认需要) form.append($('<input>', { type: 'hidden', name: '__RequestVerificationToken', value: $('input[name="__RequestVerificationToken"]').val() })); // 提交表单 form.appendTo('body').submit(); // 关闭模态框 $("#deleteModal").modal('hide'); }); }()));
3. 控制器代码(可选优化)
如果希望更符合REST规范,可以将方法改为接受DELETE请求,同时兼容POST:
[HttpPost, HttpDelete] [ValidateAntiForgeryToken] public IActionResult DeletePOST(int? id) { var selectedEmployee = _db.Employees.Find(id); if (selectedEmployee == null) { return NotFound(); } _db.Employees.Remove(selectedEmployee); _db.SaveChanges(); return RedirectToAction("Index"); }
如果改用DELETE请求,JavaScript中需要修改表单的method为DELETE,Asp.Net Core默认已支持HTTP DELETE方法,防伪令牌仍需包含。
关于控制台警告
crbug/1173575, non-JS module files deprecated是Chrome浏览器的警告,和删除功能无关,是浏览器对非JS模块文件加载方式的提示,无需处理。
内容的提问来源于stack exchange,提问作者user17195990

