基于JavaScript Fetch的.NET MVC参数传递问题
问题
维护一个已升级至.NET 8的C# MVC遗留系统,前端原用jQuery AJAX调用后端接口正常,切换为Fetch API时遇到参数传递问题:
后端接口定义:
public IActionResult SearchCerts(string Company, string ExpStart, string ExpEnd) { // 业务逻辑 return PartialView("_SearchResults", Results); }
原AJAX代码:
function SearchCerts() { $.ajax({ url: "/Certs/SearchCerts", data: { Company: document.getElementById("edtSearchCompany").value, ExpStart: document.getElementById("edtSearchExpires1").value, ExpEnd: document.getElementById("edtSearchExpires2").value }, dataType: "html", async: true, success: function (data) { $('#divSearchResults').html(data); }, error: function () { alert("Error"); } }); }
使用Fetch API时,尝试用JSON.stringify传递对象,后端接收的参数全为null:
async function SearchCertsExecute() { var SendData = { Company: document.getElementById("edtSearchCompany").value, ExpStart: document.getElementById("edtSearchExpires1").value, ExpEnd: document.getElementById("edtSearchExpires2").value }; let Results = await fetch("/Certs/SearchCerts", { method: 'POST', body: JSON.stringify(SendData) }); if (Results.ok) { var data = await Results.text(); $('#divSearchResults').html(data); } else { alert("HTTP-Error: " + Results.status); } }
目前仅能通过修改后端接收IFormCollection参数、前端传递FormData的方式实现参数传递,但希望保留原后端接口结构。
原因与解决方法
核心原因
jQuery AJAX默认会把data对象序列化为application/x-www-form-urlencoded格式的表单数据,并自动设置对应的Content-Type请求头,ASP.NET MVC的默认模型绑定可以直接识别这种格式并绑定到单个参数上。
而你用JSON.stringify传递时,存在两个问题:
- 没有设置
Content-Type: application/json请求头,后端无法识别请求体是JSON格式,仍按表单格式解析,自然拿不到数据。 - 即使设置了请求头,ASP.NET MVC默认不会从JSON请求体中绑定单个参数(
string Company这类),需要显式配置或封装参数为类。
解决方法一:保持后端接口不变,用表单格式传递(和AJAX行为一致)
将JavaScript对象转为application/x-www-form-urlencoded格式,并设置对应请求头:
async function SearchCertsExecute() { const SendData = { Company: document.getElementById("edtSearchCompany").value, ExpStart: document.getElementById("edtSearchExpires1").value, ExpEnd: document.getElementById("edtSearchExpires2").value }; // 转换为urlencoded格式 const formData = new URLSearchParams(SendData); const Results = await fetch("/Certs/SearchCerts", { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: formData }); if (Results.ok) { const data = await Results.text(); $('#divSearchResults').html(data); } else { alert("HTTP-Error: " + Results.status); } }
这种方式完全匹配原AJAX的请求格式,后端无需任何修改即可正常接收参数。
解决方法二:改用JSON格式传递,调整后端接口
如果希望用JSON格式传递,需要调整后端接口以支持JSON请求体绑定:
步骤1:创建请求DTO类
public class SearchCertsRequest { public string Company { get; set; } public string ExpStart { get; set; } public string ExpEnd { get; set; } }
步骤2:修改后端接口,添加[FromBody]特性
public IActionResult SearchCerts([FromBody] SearchCertsRequest request) { // 使用request.Company、request.ExpStart、request.ExpEnd获取参数 return PartialView("_SearchResults", Results); }
步骤3:前端Fetch设置正确请求头
async function SearchCertsExecute() { const SendData = { Company: document.getElementById("edtSearchCompany").value, ExpStart: document.getElementById("edtSearchExpires1").value, ExpEnd: document.getElementById("edtSearchExpires2").value }; const Results = await fetch("/Certs/SearchCerts", { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(SendData) }); if (Results.ok) { const data = await Results.text(); $('#divSearchResults').html(data); } else { alert("HTTP-Error: " + Results.status); } }
注意:[FromBody]特性只能在一个参数上使用,因此需要将多个参数封装为一个类对象。
内容的提问来源于stack exchange,提问作者TheNeil
相关产品推荐
相关产品推荐

