ASP.NET Core Web API模板中PUT、DELETE请求报404问题求助
PUT/DELETE请求返回404的排查与解决步骤
优先排查代码层路由匹配问题(80%的这类问题根源不在IIS配置)
先看你贴的两个Action的写法,本身就存在容易导致路由不匹配的问题:
- 确认控制器类的全局路由配置:先检查ClientsController类的定义上有没有标注全局路由特性,比如
[Route("api/[controller]")]、[ApiController]。如果没有全局路由前缀,你现在Update方法上写的[HttpPut("{id:length(24)}")]生成的匹配路径是没有api/Clients前缀的,实际匹配的是根路径下的24位id,和你发请求用的/api/Clients/xxx路径根本对不上,自然会404。 - 排查Action上的路由冲突:你写的Delete方法同时叠加了
[HttpDelete("{id:length(24)}")]和[Route("api/Clients/{id}")]两个独立的路由特性。特性路由的核心规则是:同一个Action上如果写了多个独立路由模板,会生成多条独立的路由规则——这就导致你现在Delete方法同时匹配两个规则:一个是不带id长度约束、不限制HTTP谓词的api/Clients/{id},另一个是仅匹配DELETE请求、要求id必须为24位长度的路由。路由匹配的时候如果你的请求id长度不对、或者优先级判断出问题,就会直接匹配失败抛404,根本走不到方法内部的client==null判断逻辑。 - 快速定位路由问题的调试方法:在Program.cs的端点配置里加临时调试接口,遍历所有已注册的路由规则,就能看到你发的请求到底有没有对应的匹配项:
app.UseEndpoints(endpoints => { endpoints.MapControllers(); // 临时调试接口,访问/route-debug就能列出所有注册的路由 endpoints.MapGet("/route-debug", async context => { var endpointSource = context.RequestServices.GetRequiredService<EndpointDataSource>(); await context.Response.WriteAsJsonAsync(endpointSource.Endpoints.Select(e => new { e.DisplayName, RoutePattern = (e as RouteEndpoint)?.RoutePattern.RawText, HttpMethods = (e as RouteEndpoint)?.Metadata.GetMetadata<HttpMethodMetadata>()?.HttpMethods })); }); });
IIS层剩余配置排查
你已经试过移除WebDav模块,这部分不用重复操作,重点检查容易漏的配置项:
- 检查请求过滤规则:打开IIS对应站点的“请求筛选”面板,切到“HTTP谓词” tab,确认PUT、DELETE没有被列在拒绝列表里。很多站点默认的请求过滤规则只允许GET、POST、HEAD请求,未授权的谓词会在IIS层直接返回404,根本不会把请求转发到你的应用。
- 检查web.config中的处理器配置:确认ASP.NET Core模块(ANCM)的handler配置没有限制HTTP谓词,正确的配置应该是接收所有谓词的请求:
如果你这里的<handlers> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" /> </handlers>verb属性写了"GET,POST",那PUT、DELETE请求根本不会被转发到应用,直接被IIS拦截。 - 确认应用池的管道模式:必须选择集成管道模式,经典管道模式下托管模块不会对非GET/POST的请求做处理,会直接返回404。
现有代码的修正方案
对照你的业务逻辑,修正后的正确写法应该是:
- 先给控制器类加全局路由和API控制器特性:
[Route("api/[controller]")] // 全局路由前缀,自动生成api/Clients路径 [ApiController] public class ClientsController : ControllerBase { // 原有Update方法逻辑保持不变,路由自动拼接为api/Clients/{id},仅匹配PUT请求、要求id为24位长度 [HttpPut("{id:length(24)}")] public IActionResult Update(string id, Client clientIn) { var client = _clientService.Get(id); if (client == null) return NotFound(); _clientService.Update(id, clientIn); return NoContent(); } // 删除原有方法上多余的[Route("api/Clients/{id}")]特性,避免路由冲突 [HttpDelete("{id:length(24)}")] public IActionResult Delete(string id) { var client = _clientService.Get(id); if (client == null) return NotFound(); _clientService.Remove(client.ClientId); return NoContent(); } }
兜底验证逻辑
改完配置后如果还是404,用最简单的方法定位故障层:临时把两个Action的HTTP谓词改成POST,比如给Update加[HttpPost("Update/{id:length(24)}")],发POST请求测试:
- 如果POST请求能正常进入方法、返回预期结果,PUT/DELETE还是404:说明问题出在IIS层的谓词拦截,和代码逻辑无关;
- 如果POST请求也进不去、还是404:说明问题出在路由模板拼接错误,和HTTP谓词没有关系。
内容的提问来源于stack exchange,提问作者utkarsh Kendre
相关产品推荐
相关产品推荐

