React Native使用fetch发送FormData至Node API失败求助
Hey there, I’ve run into this exact issue before with Expo 35 and React Native 0.59 on Android—FormData handling for file uploads was super finicky back then. Let’s break down what was going wrong and the solutions that work, including the base64 approach you landed on.
Root Cause
The core problem here is that older Expo/React Native versions had inconsistent handling of FormData with file URIs, especially on Android. When you appended the image object directly to FormData, the fetch implementation couldn’t properly parse the file:// URI into a readable stream for the request, leading to the network failure. Even when sending plain string FormData, auto-generated (or manual) content-type headers didn’t set correctly, resulting in an empty body on the server side.
Solution 1: Base64 Encoding (Your Working Fix)
This is a reliable workaround for older Expo versions since it avoids FormData’s file handling entirely. Here’s the end-to-end implementation:
React Native/Expo Side
- Modify your image picker to retrieve the base64 string:
import * as ImagePicker from 'expo-image-picker'; const pickImage = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, allowsEditing: true, quality: 0.8, base64: true, // Enable base64 encoding for the image }); if (!result.cancelled) { const filename = result.uri.split('/').pop(); await uploadImageAsBase64(result.base64, filename); } };
- Send the base64 string and metadata via a JSON request:
const uploadImageAsBase64 = async (base64Image, filename) => { try { const response = await fetch(`${serverIp}/manageFiles/almacenImagenes`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ fromApp: "true", userId: "testID123", imageBase64: base64Image, filename: filename }) }); const resData = await response.json(); console.log("Upload successful:", resData); } catch (err) { console.log("Upload error:", err); } };
Node.js Server Side
Decode the base64 string and save it as a file:
const fs = require('fs'); const path = require('path'); app.post('/manageFiles/almacenImagenes', async (req, res) => { try { const { imageBase64, filename, userId } = req.body; // Strip the optional data URI prefix added by Expo const base64Data = imageBase64.replace(/^data:image\/jpeg;base64,/, ''); const uploadPath = path.join(__dirname, 'uploads', `${userId}_${filename}`); fs.writeFileSync(uploadPath, base64Data, 'base64'); res.status(200).json({ success: true, message: "Image saved successfully" }); } catch (err) { res.status(500).json({ success: false, error: err.message }); } });
Solution 2: Fixing FormData for Older Expo Versions
If you prefer to stick with FormData, these tweaks might resolve the network error:
- Skip manual
Content-Typeheaders: When usingFormData, fetch automatically generates the correctmultipart/form-dataheader with a boundary value. Manually setting this header breaks the request, as the boundary won’t match the body. - Adjust the image URI for Android: Use Expo’s
FileSystemmodule to convert thefile://URI to acontent://URI, which older React Native versions handle better:
import * as FileSystem from 'expo-file-system'; // Resolve the correct content URI const contentUri = await FileSystem.getContentUriAsync(image.uri); let formData = new FormData(); formData.append("imageFile", { uri: contentUri, type: "image/jpeg", name: filename }); // Append metadata as individual fields (not objects!) formData.append("fromApp", "true"); formData.append("userId", "testID123");
Important: Never append objects directly to FormData in older Expo versions—each key-value pair needs to be added separately.
- Validate server CORS settings: Ensure your Node server accepts
multipart/form-datarequests and has proper CORS configuration. Using thecorsmiddleware:
const cors = require('cors'); // Allow your Expo app's origin in production (use "*" for testing only) app.use(cors({ origin: '*', credentials: true }));
Final Notes
For Expo 35 specifically, the base64 method is the most stable choice because it bypasses the FormData bugs that plagued that version. If you ever upgrade to Expo v40+, FormData file uploads work much more reliably out of the box.
内容的提问来源于stack exchange,提问作者KOseare

