使用Axios上传含JSON与图片的FormData时后端无法接收JSON字段问题
问题解决:Axios上传FormData时JSON对象无法被ASP.NET Core后端解析
问题场景
用Axios上传包含图片和JSON对象的FormData时,遇到两种情况:
- 将JSON对象转为字符串后以
createStoryModel字段加入FormData,后端能接收图片,但无法获取JSON中的字段值 - 逐个将JSON对象的字段加入FormData,后端能正常接收所有值,但字段过多时操作繁琐
前端代码对比
无效实现(无法解析JSON字段)
export async function createStoryAsync(Title, Category, formFile) { let formData = new FormData(); // 将对象转为JSON字符串后加入FormData const json = JSON.stringify({ Title, Category }); formData.append("createStoryModel", json); formData.append("formFile", formFile[0]); await axios.post(`${baseURL}/create`, formData); }
请求Payload:
FORMDATA: createStoryModel: {"Title":"FADFASD","Category":"fdasfds"} formFile: (binary)
有效但繁琐的实现
export async function createStoryAsync(Title, Category, formFile) { let formData = new FormData(); // 逐个添加对象字段 formData.append("Title", Title); formData.append("Category", Category); formData.append("formFile", formFile[0]); await axios.post(`${baseURL}/create`, formData); }
请求Payload:
FORMDATA: Title: 123 Category: 12 formFile: (binary)
后端代码
实体类
public class CreateStoryModel { public string? Title { get; set; } public string? Category { get; set; } }
控制器接口
[HttpPost("create")] public async Task<ActionResult> CreateAsync([FromForm]CreateStoryModel createStoryModel, IFormFile? FormFile) { // 业务逻辑 }
原因分析
ASP.NET Core的[FromForm]特性默认是解析FormData中的扁平键值对,它会把FormData里的每个字段直接映射到实体类的对应属性上。而如果把JSON字符串作为单个字段传递,后端无法自动将这个字符串反序列化为CreateStoryModel实体,导致属性值为空。
解决方案
方案1:自动遍历对象字段批量添加到FormData(推荐)
写一个工具函数,自动遍历JSON对象的所有属性并添加到FormData,避免手动逐个操作:
// 工具函数:将对象的所有属性批量添加到FormData function appendModelToFormData(formData, model) { for (const [key, value] of Object.entries(model)) { formData.append(key, value); } } // 使用示例 export async function createStoryAsync(Title, Category, formFile) { let formData = new FormData(); const createStoryModel = { Title, Category }; // 自动添加所有字段 appendModelToFormData(formData, createStoryModel); formData.append("formFile", formFile[0]); await axios.post(`${baseURL}/create`, formData); }
如果是嵌套对象,可以修改工具函数支持递归:
function appendModelToFormData(formData, model, parentKey = '') { for (const [key, value] of Object.entries(model)) { const currentKey = parentKey ? `${parentKey}.${key}` : key; if (typeof value === 'object' && value !== null && !(value instanceof File)) { appendModelToFormData(formData, value, currentKey); } else { formData.append(currentKey, value); } } }
方案2:修改后端接收逻辑(不推荐)
如果不想改动前端,可以将后端的参数改为字符串类型,手动反序列化JSON:
[HttpPost("create")] public async Task<ActionResult> CreateAsync([FromForm]string createStoryModel, IFormFile? FormFile) { // 手动将JSON字符串反序列化为实体类 var model = System.Text.Json.JsonSerializer.Deserialize<CreateStoryModel>(createStoryModel); // 后续业务逻辑 }
内容的提问来源于stack exchange,提问作者Peng
相关产品推荐
相关产品推荐

