React调用ASP.NET Core 3.0控制器方法遇端点冲突及响应异常
你的问题核心在于路由配置重复导致请求无法匹配到正确的控制器方法,进而返回了非预期内容(比如manifest文件)。咱们一步步拆解解决:
问题根源:路由路径重复定义
你的控制器上已经标注了[Route("api/[controller]")],这意味着所有该控制器下的API都会以api/Article作为基础路径([controller]会自动替换为控制器名称Article)。但你在每个方法上又重复写了完整的路由前缀[Route("api/[controller]/getarticles")],最终生成的实际路由会变成:api/Article/api/Article/getarticles
这和你前端请求的api/article/getarticles/?id=xxx完全不匹配,服务器找不到对应的方法,就返回了默认的静态文件(比如manifest),而非你期望的JSON响应。
修正方案:调整路由配置
我们需要简化方法级别的路由,让它基于控制器的基础路径做相对配置,同时推荐使用ASP.NET Core的[ApiController]特性增强API功能:
修正后的控制器代码
[ApiController] // 启用API控制器特性,自动处理模型绑定、验证等 [Route("api/[controller]")] public class ArticleController : ControllerBase // API控制器推荐继承ControllerBase(无视图相关功能) { private readonly DzikanContext _context; public ArticleController(DzikanContext context) { _context = context; } // 实际路由:GET api/article/getarticles?id=xxx [HttpGet("getarticles")] // 相对路由,追加在控制器基础路径后 public IActionResult GetArticles(int id) { var titles = _context.Post.Where(p => p.TypeId == id).Select(p => p); var filtered = titles.Skip(Math.Max(0, titles.Count() - 3)).ToList(); Dictionary<int, string> icons = new Dictionary<int, string> { {1, "someUrl" }, {2, "someUrl2"}, {3, "someUrl3" } }; List<PostsPayload> articles = new List<PostsPayload>(); foreach (var title in filtered) { articles.Add(new PostsPayload { IconUrl = icons[title.ResourceId], ArticleBody = title.Title }); } return Json(articles.ToArray()); } // 实际路由:GET api/article/makenewpost?id=xxx [HttpGet("makenewpost")] // 相对路由,追加在控制器基础路径后 public IActionResult MakeNewPost(int id) { var articles = _context.Post.Where(p => p.Id == id).Select(p => p); var title = articles.Select(p => p.Title).First(); var body = articles.Select(p => p.Body).First(); List<Post> posts = new List<Post>{ new Post { Title = title, Body = body } }; return Json(posts.ToArray()); } }
前端请求验证
你的现有前端fetch代码不需要修改,因为请求URLapi/article/getarticles/?id= + this.props.id已经和修正后的路由完全匹配:
async fetchData() { const response = await fetch('api/article/getarticles/?id=' + this.props.id); const data = await response.json(); this.setState({ blocktitle: this.props.blocktitle, data: data, id: this.props.id }); }
额外优化建议
使用路由参数代替查询字符串:如果想让API更符合REST风格,可以把参数放到路由路径中,比如:
[HttpGet("getarticles/{id}")] public IActionResult GetArticles(int id) { ... }前端请求改为:
fetch('api/article/getarticles/' + this.props.id)处理空参数/不存在的数据:比如当
id为空或者数据库中找不到对应数据时,返回明确的状态码,让前端能更清晰地处理异常:if (!id.HasValue) return BadRequest("Id参数不能为空"); var article = _context.Post.FirstOrDefault(p => p.Id == id.Value); if (article == null) return NotFound("未找到对应文章");
验证效果
修正路由后,重新启动后端服务,前端发起请求就能正确匹配到对应的控制器方法,获取到预期的JSON响应了,同时也解决了之前的多端点冲突问题。
内容的提问来源于stack exchange,提问作者Timofey Melentev

