如何在Expo ReactNative中通过AXIOS POST将expo-picker-image图片保存至服务器?
解决Expo图片通过Axios上传至Django DRF无报错但未保存的问题
前端(Expo + Axios)排查与修正
1. 正确处理Expo ImagePicker返回的图片
Expo ImagePicker返回的uri是本地文件路径,必须转换成Blob才能被后端识别为文件,直接传入uri会导致上传失败。
示例代码:
import { ImagePicker } from 'expo-image-picker'; import axios from 'axios'; const pickAndUploadImage = async () => { const pickResult = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, allowsEditing: true, quality: 1, }); if (!pickResult.canceled) { // 将Expo本地uri转为Blob const blobResp = await fetch(pickResult.assets[0].uri); const imageBlob = await blobResp.blob(); // 构造FormData const formData = new FormData(); // 字段名`image`需和后端序列化器字段完全一致 formData.append('image', imageBlob, `upload-${Date.now()}.jpg`); try { const uploadResp = await axios.post('http://你的DRF接口地址/upload/', formData, { headers: { // 禁止手动设置Content-Type!Axios会自动生成带boundary的请求头,手动设置会导致解析失败 } }); console.log('上传成功,图片地址:', uploadResp.data.image_url); } catch (err) { console.error('上传失败:', err.response?.data || err.message); } } };
2. 前端关键注意点
- 不要手动设置
Content-Type: multipart/form-data,Axios会自动处理并添加必要的boundary标识。 - FormData的append第三个参数是文件名,建议添加以帮助后端识别文件类型。
后端(Django DRF)配置与实现
1. 配置媒体文件存储路径
在项目settings.py中添加:
MEDIA_ROOT = BASE_DIR / 'media' MEDIA_URL = '/media/'
开发环境下,在根urls.py中添加媒体文件访问路由:
from django.conf import settings from django.conf.urls.static import static urlpatterns = [ path('api/', include('你的APP.urls')), # 其他路由... ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
2. 定义模型与序列化器
# models.py from django.db import models class UploadedImage(models.Model): # upload_to指定文件存储的子目录,会自动创建 image = models.ImageField(upload_to='user_uploads/') uploaded_at = models.DateTimeField(auto_now_add=True) # serializers.py from rest_framework import serializers from .models import UploadedImage class UploadedImageSerializer(serializers.ModelSerializer): # 序列化时返回完整可访问的图片URL image_url = serializers.SerializerMethodField() class Meta: model = UploadedImage fields = ['id', 'image', 'image_url', 'uploaded_at'] def get_image_url(self, obj): request = self.context.get('request') return request.build_absolute_uri(obj.image.url)
3. 编写上传视图
# views.py from rest_framework import status from rest_framework.response import Response from rest_framework.views import APIView from .serializers import UploadedImageSerializer class ImageUploadView(APIView): def post(self, request): # 传入request上下文用于生成完整URL serializer = UploadedImageSerializer(data=request.data, context={'request': request}) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
4. 配置APP路由
在APP的urls.py中:
from django.urls import path from .views import ImageUploadView urlpatterns = [ path('upload/', ImageUploadView.as_view(), name='image-upload'), ]
快速排查清单
- 前端:打印
formData.get('image')确认是否为Blob对象,而非字符串uri。 - 后端:
- 检查
MEDIA_ROOT目录是否有读写权限,确保Django进程能创建文件。 - 在视图中打印
request.FILES,确认是否接收到上传的文件。 - 核对序列化器字段名与前端FormData的键是否完全一致。
- 检查
- 跨域:若前后端域名不同,需配置Django跨域(可使用
django-cors-headers库)。
内容的提问来源于stack exchange,提问作者Eder Juárez
相关产品推荐
相关产品推荐

