如何通过React Native(Expo)实时获取相机图片并上传至Azure Blob存储?
Expo相机实时拍照上传至Azure Blob存储方案
你已经实现了通过表单上传图片到Azure Blob的Flask后端,现在只需要在Expo端完成实时拍照并构造符合后端要求的请求即可,以下是完整实现步骤:
一、Expo前端实现
1. 安装必要依赖
首先在Expo项目中安装相机相关依赖:
npx expo install expo-camera expo-image-picker
2. 相机拍照与上传代码示例
创建一个拍照上传组件,核心逻辑是调用相机拍照、将图片转为FormData、附带其他表单字段发送POST请求到你的Flask接口:
import { useState, useEffect } from 'react'; import { View, Button, Alert, Text } from 'react-native'; import { Camera } from 'expo-camera'; export default function CameraUploadScreen() { const [hasPermission, setHasPermission] = useState(null); const [cameraRef, setCameraRef] = useState(null); const [type, setType] = useState(Camera.Constants.Type.back); // 请求相机权限 useEffect(() => { (async () => { const { status } = await Camera.requestCameraPermissionsAsync(); setHasPermission(status === 'granted'); })(); }, []); // 拍照并上传 const takePictureAndUpload = async () => { if (cameraRef) { try { // 拍照获取图片 const photo = await cameraRef.takePictureAsync({ quality: 0.8 }); // 构造FormData,匹配后端接收的字段 const formData = new FormData(); // 添加图片文件 formData.append('file', { uri: photo.uri, name: `incident_${Date.now()}.jpg`, // 自定义文件名 type: 'image/jpeg' }); // 添加其他表单字段(根据业务需求填写实际值) formData.append('damage_type', '碰撞'); formData.append('damage_parts', '保险杠'); formData.append('location_address', '北京市朝阳区XX路'); formData.append('geolocation_latitude', '39.9042'); formData.append('geolocation_longitude', '116.4074'); formData.append('datetime', new Date().toISOString()); formData.append('created_by', 'user123'); formData.append('created_on', new Date().toISOString()); formData.append('modified_by', 'user123'); formData.append('modified_on', new Date().toISOString()); formData.append('customer_id', 'cust456'); // 发送POST请求到Flask后端 const response = await fetch('http://你的Flask服务器地址/api/addincident', { method: 'POST', body: formData, headers: { 'Content-Type': 'multipart/form-data' } }); if (response.ok) { const imageUrl = await response.text(); Alert.alert('上传成功', `图片地址:${imageUrl}`); } else { Alert.alert('上传失败', '请检查网络或后端服务'); } } catch (error) { console.error('拍照或上传出错:', error); Alert.alert('错误', '拍照或上传过程中出现问题'); } } }; if (hasPermission === null) { return <View />; } if (hasPermission === false) { return <Text>无相机访问权限</Text>; } return ( <View style={{ flex: 1 }}> <Camera style={{ flex: 1 }} type={type} ref={ref => setCameraRef(ref)} /> <View style={{ position: 'absolute', bottom: 20, alignSelf: 'center' }}> <Button title="拍照并上传" onPress={takePictureAndUpload} /> </View> </View> ); }
二、Flask后端优化修正
你的现有后端代码已经可以处理上传请求,但存在两个必须修正的问题:
1. 地理位置字段取值错误
原代码中geolocation_longitude错误地取了geolocation_latitude的值,导致经纬度数据混乱,修正如下:
geolocation_longitude = request.form.get('geolocation_longitude') # 原代码写的是geolocation_latitude
2. 异常处理语法错误
原代码中print('Exception=' + Exception)是语法错误,无法正确打印异常信息,修正为:
try: blob_service.create_blob_from_stream(container, filename, file) except Exception as e: print(f'Exception={str(e)}') pass
3. 可选优化:添加状态码返回
为了让前端更清晰地判断请求结果,建议在返回时附带HTTP状态码:
# 上传成功返回 return image_filepath, 200 # 若上传失败,可返回错误提示与状态码 # return '图片上传失败', 500
关键注意事项
- Expo中构造
FormData时,文件必须包含uri、name、type三个字段,否则后端无法识别为文件类型 - 本地测试时,Flask服务器需启动为
app.run(host='0.0.0.0', port=5000),确保同一局域网内的Expo设备可以访问 - 可通过
takePictureAsync的quality参数调整图片质量,平衡文件大小与清晰度
内容的提问来源于stack exchange,提问作者Tharshika Elangovan
相关产品推荐
相关产品推荐

