React Native使用Expo Image Picker+Axios上传图片至服务器失败求助
Expo ImagePicker 图片上传失败问题排查与修复
我使用expo-image-picker作为UI组件实现图片上传功能,但图片始终无法上传到后端,尝试多种方法均未解决。以下是我的原代码实现:
1. 图片状态设置逻辑
const showImagePicker = async () => { Promise.all([ImagePicker.requestMediaLibraryPermissionsAsync(), ImagePicker.requestCameraPermissionsAsync()]).then(result => { result.forEach(permission => { return !permission.granted; }); }); const result: ImagePicker.ImageInfo = (await ImagePicker.launchImageLibraryAsync({ base64: true, })) as ImagePicker.ImageInfo; const uriParts = result.uri.split('.'); const fileType = uriParts[uriParts.length - 1]; if (!result.cancelled) { setPickedImagePath({ uri: Platform.OS === 'android' ? result.uri : result.uri.replace('file://', ''), name: `photo.${fileType}`, type: `application/${fileType}`, }); } };
2. FormData追加数据逻辑
const createRequestCall = async () => { const formData = new FormData(); formData.append('file', pickedImage.uri); formData.append('data2', 'test'); formData.append('data3', '123'); formData.append('data4', 'test'); dispatch(uploadPhoto(formData)); };
3. 请求分发逻辑
export const uploadPhoto= (photoRequest: FormData) => async (dispatch: Dispatch<Action>): Promise<void> => { dispatch({ type: ActionTypes.API_LOADING, payload: apiIsLoading }); const response = await Apis.requestPhoto(fileRequest); dispatch({ type: ActionTypes.API_LOADING, payload: apiIsNotLoading }); };
4. 后端请求逻辑
async requestPhoto(data: FormData): Promise<IDetails> { const response = await http.post<IDetails, AxiosResponse<ITripDetailsResponse>>(`${baseURL}/upload/image`, data, { headers: { 'Content-Type': 'multipart/form-data' }, transformRequest(formData, headers) { return data; }, }); return response.data; },
问题分析与修复方案
1. 权限请求逻辑错误
原代码未等待权限请求结果,也未正确判断权限是否授予,forEach内的return无法终止后续代码,会导致无权限时仍执行选图逻辑。同时图片MIME类型设置错误,应该用image/xxx而非application/xxx。
修正后代码:
const showImagePicker = async () => { // 等待权限请求完成 const [mediaPerm, cameraPerm] = await Promise.all([ ImagePicker.requestMediaLibraryPermissionsAsync(), ImagePicker.requestCameraPermissionsAsync() ]); // 权限未授予则终止流程 if (!mediaPerm.granted || !cameraPerm.granted) { alert('需要授予图片访问权限才能上传'); return; } const result: ImagePicker.ImageInfo = (await ImagePicker.launchImageLibraryAsync({ base64: true, })) as ImagePicker.ImageInfo; if (result.cancelled) return; // 正确识别图片MIME类型 const fileType = result.uri.split('.').pop(); let mimeType = 'image/jpeg'; if (fileType === 'png') mimeType = 'image/png'; else if (fileType === 'gif') mimeType = 'image/gif'; setPickedImagePath({ uri: Platform.OS === 'android' ? result.uri : result.uri.replace('file://', ''), name: `photo.${fileType}`, type: mimeType, }); };
2. FormData追加文件错误
原代码仅传递图片uri字符串,FormData需要接收包含uri、name、type的完整对象才能识别为文件。
修正后代码:
const createRequestCall = async () => { if (!pickedImage) return; // 先判断是否选中图片 const formData = new FormData(); // 传入完整的文件对象 formData.append('file', pickedImage as any); formData.append('data2', 'test'); formData.append('data3', '123'); formData.append('data4', 'test'); dispatch(uploadPhoto(formData)); };
3. 请求分发逻辑变量名错误
原代码入参为photoRequest,但调用接口时用了未定义的fileRequest,导致参数传递错误。
修正后代码:
export const uploadPhoto = (photoRequest: FormData) => async (dispatch: Dispatch<Action>): Promise<void> => { dispatch({ type: ActionTypes.API_LOADING, payload: apiIsLoading }); // 使用正确的入参变量名 const response = await Apis.requestPhoto(photoRequest); dispatch({ type: ActionTypes.API_LOADING, payload: apiIsNotLoading }); };
4. 后端请求配置错误
手动设置Content-Type: multipart/form-data会丢失自动生成的boundary,Axios会自动处理FormData的Content-Type;多余的transformRequest会干扰默认的表单数据转换。
修正后代码:
async requestPhoto(data: FormData): Promise<IDetails> { const response = await http.post<IDetails, AxiosResponse<ITripDetailsResponse>>( `${baseURL}/upload/image`, data ); return response.data; },
内容的提问来源于stack exchange,提问作者coder03
相关产品推荐
相关产品推荐

