React Native使用ImagePicker向.NET Core API发Post请求遇400错误
我来帮你搞定这个上传的400错误问题,之前我也踩过类似的坑,核心问题出在参数传递方式不对和前后端FormData格式不匹配上,咱们分客户端和服务端一步步修复:
一、React Native客户端代码修正
1. 先把Axios的参数传对
你现在把fotos作为Axios post的第三个参数传了,但Axios的post方法第三个参数是请求配置(比如headers),不是请求数据。得把fotos的字段合并到FormData里,或者作为URL参数带过去。
2. 对齐前后端的字段名
后端接收文件的参数是IFormFileCollection arquivo,所以你在FormData里append文件的时候,key必须是arquivo,而不是file,不然后端识别不到文件集合。
3. 处理跨平台的URI差异
React Native的ImagePicker在iOS和Android返回的URI格式不一样:iOS是file://开头,Android可能是content://,得统一处理成Axios能正确解析的格式,最简单的就是给iOS的URI去掉file://前缀。
修改后的客户端代码:
handledUpload = async () => { // 把async提到外层,避免嵌套async的麻烦 try { const upload = await ImagePicker.launchImageLibrary({}); // 用await更直观,避免回调嵌套 if (!upload.uri) return; // 用户取消选择的情况直接返回 const arquivo = new FormData(); // 处理URI格式:iOS去掉file://前缀,Android保持原样 const fileUri = Platform.OS === 'ios' ? upload.uri.replace('file://', '') : upload.uri; // 注意key是'arquivo',和后端参数名严格一致 arquivo.append('arquivo', { uri: fileUri, type: upload.type || 'image/jpeg', // 兜底类型,防止返回null导致错误 name: upload.fileName || `img-${Date.now()}.jpg` // 兜底文件名,避免无文件名的情况 }); // 把fotos的字段逐个加到FormData里 arquivo.append('Id', '1'); arquivo.append('IdUsuario', '1'); arquivo.append('NumCode', '4'); // 发送请求,这里不需要额外传fotos参数 const response = await api.post(`galeria/UploadArquivos/`, arquivo, { headers: { // 让Axios自动处理multipart/form-data的boundary,别手动写boundary,会出错 'Content-Type': 'multipart/form-data' } }); console.log('上传成功啦:', response.data); } catch (error) { // 打印详细错误信息,方便调试 console.error('上传失败:', error.response?.data || error.message); } };
二、.NET Core服务端代码修正
1. 给参数加上[FromForm]标记
因为是multipart/form-data请求,必须告诉框架从表单里读取参数,所以要给arquivo和fotos都加上[FromForm]标记。另外,你的Consumes属性可以只保留multipart/form-data,因为上传文件只用这个类型。
修改后的服务端代码:
[HttpPost] [Route("UploadArquivos")] [Consumes("multipart/form-data")] // 只保留需要的类型即可 public IEnumerable<Galeria> UploadArquivos([FromForm] IFormFileCollection arquivo, [FromForm] Galeria fotos) { // 现在可以正常拿到文件和fotos数据了,先加个调试输出看看 if (arquivo != null && arquivo.Count > 0) { foreach (var file in arquivo) { Console.WriteLine($"收到文件:{file.FileName},大小:{file.Length}字节"); } } Console.WriteLine($"Fotos参数:Id={fotos.Id}, IdUsuario={fotos.IdUsuario}, NumCode={fotos.NumCode}"); // 接下来写你的文件存储逻辑就行 return new List<Galeria>(); // 按你的业务需求返回数据 }
可选:如果不想拆fotos字段(进阶方式)
要是你不想把fotos的字段一个个拆到FormData里,也可以在客户端把fotos转成JSON字符串,append到FormData里,后端再反序列化:
客户端追加一行:
arquivo.append('fotos', JSON.stringify({ Id: 1, IdUsuario: 1, NumCode: 4 }));
服务端修改参数:
public IEnumerable<Galeria> UploadArquivos([FromForm] IFormFileCollection arquivo, [FromForm] string fotos) { var galeria = JsonSerializer.Deserialize<Galeria>(fotos); // 后续逻辑和之前一样 }
三、调试小技巧
- 客户端看请求详情:给Axios加个拦截器,打印请求的headers和FormData内容,确认参数是不是和你预期的一样;
- 用Postman先测后端:先在Postman里构造一个
multipart/form-data请求,上传文件+参数,测试后端接口是否正常,排除后端本身的问题; - 检查CORS配置:确保后端的CORS允许你的React Native应用访问,并且允许
multipart/form-data请求类型。
内容的提问来源于stack exchange,提问作者WashingtonGreed

