Postman无法向ASP.Net WebAPI 2控制器发POST请求,但GET请求正常
核心问题
你的POST请求返回404,本质是WebAPI参数绑定规则不匹配,而GET请求能工作是因为WebAPI的路由约定冲突。
参数绑定问题
WebAPI对简单类型(如string)的默认绑定逻辑是:从URI查询字符串中获取参数,而非请求体的JSON。当你用POST发送JSON格式的UserId到请求体时,控制器方法的string UserId参数无法获取到值,WebAPI认为没有匹配的Action,因此返回404。
GET请求异常工作的原因
尽管你给方法加了[HttpPost]属性,但WebAPI的约定路由(若你在WebConfig中配置了默认路由)会根据动作名前缀(GetProfile以Get开头)自动匹配GET请求,忽略了[HttpPost]的限制。如果你的控制器同时存在属性路由和约定路由,就会出现这种不符合预期的匹配。
解决方法
方法1:用[FromBody]强制从请求体获取简单类型参数
修改控制器方法,给UserId参数添加[FromBody]特性,告诉WebAPI从请求体解析该参数:
[Route("api/GetProfile")] [HttpPost] public async Task<IHttpActionResult> GetProfile([FromBody] string UserId) { var retval = new Profile(); if (UserId != null) { if (await dbv.IsValidUserIdAsync(UserId)) { retval = await profile_Data.GetProfileAsync(UserId); } } return Ok(retval); }
注意:此时PostMan的RAW JSON内容需要改为纯字符串,不能是键值对对象:
"69d40311-f9e0-4499-82ea-959949fc34fe"
方法2:使用DTO类接收参数(推荐,扩展性更强)
定义一个DTO类来封装请求参数:
public class GetProfileRequest { public string UserId { get; set; } }
修改控制器方法接收DTO对象:
[Route("api/GetProfile")] [HttpPost] public async Task<IHttpActionResult> GetProfile(GetProfileRequest request) { var retval = new Profile(); if (request?.UserId != null) { if (await dbv.IsValidUserIdAsync(request.UserId)) { retval = await profile_Data.GetProfileAsync(request.UserId); } } return Ok(retval); }
这种方式下,你原来的PostMan请求JSON({"UserId" : "69d40311-f9e0-4499-82ea-959949fc34fe"})可以直接使用,WebAPI会自动绑定到DTO对象。
修复GET请求的异常匹配
要彻底阻止GET请求访问该方法,确保属性路由优先:
- 在控制器类上添加
[RoutePrefix("api")]属性:
[RoutePrefix("api")] public class AccountsController : ApiController { // 你的方法... }
- 将方法的路由改为
[Route("GetProfile")]:
[Route("GetProfile")] [HttpPost] public async Task<IHttpActionResult> GetProfile(GetProfileRequest request) { // 方法内容... }
这样属性路由会完全接管,GET请求将无法匹配到该POST方法。
关于PostMan兼容性
PostMan与ASP.NET WebAPI 2.0完全兼容,问题出在WebAPI的参数绑定规则和路由配置上,和PostMan无关。
内容的提问来源于stack exchange,提问作者MC9000

