如何从React Native应用向ESP32设备POST发送二进制固件?
解决React Native向ESP32发送OTA固件时上传回调未触发的问题
核心原因分析
ESP32官方WebUpdate示例对multipart/form-data的请求格式有严格要求,React Native的FormData封装或请求配置如果和Unity的请求格式不一致,会导致ESP32无法识别上传的文件——虽然返回200 OK,但不会触发文件处理回调。
具体解决方案
1. 匹配ESP32预期的表单字段名
ESP32 WebUpdate示例默认期望文件字段名为update,必须严格对应:
const formData = new FormData(); // 第三个参数为文件名,建议和固件文件保持一致 formData.append('update', blob, 'firmware.bin');
2. 确保文件二进制数据正确读取
React Native从assets复制到文档目录后,建议通过fetch将本地文件转为Blob再封装,避免直接传文件路径可能导致的格式问题:
import RNFS from 'react-native-fs'; // 假设固件已复制到文档目录,路径为filePath const fileUri = `file://${RNFS.DocumentDirectoryPath}/firmware.bin`; const response = await fetch(fileUri); const blob = await response.blob(); const formData = new FormData(); formData.append('update', blob, 'firmware.bin');
3. 修正Axios请求配置
- 不要手动设置
Content-Type为multipart/form-data:Axios会自动根据FormData生成带正确boundary的请求头,手动设置会丢失boundary,导致ESP32无法解析表单。 - 增大超时时间:1.7MB固件上传需要一定时间,避免超时中断。
import axios from 'axios'; const config = { timeout: 30000, // 设置30秒超时 maxContentLength: Infinity, maxBodyLength: Infinity, // 禁止添加 Content-Type 配置 }; try { const response = await axios.post('http://<ESP32_IP>/update', formData, config); console.log('上传响应:', response.data); } catch (error) { console.error('上传失败:', error); }
4. 分片与缓冲的必要性
1.73MB的固件不需要手动分片,ESP32的Update库默认支持的固件大小上限通常能覆盖这个尺寸(原Unity能正常上传说明你的硬件支持)。除非后续遇到更大固件,否则无需额外处理分片或转换为缓冲数组。
调试技巧
- 抓包对比请求格式:用Charles等工具抓取Unity和React Native的请求,对比两者的请求头(尤其是boundary)、表单字段的
Content-Disposition是否一致。 - ESP32端加日志调试:在WebServer的
/update接口中添加日志,确认是否识别到文件字段:
#include <WebServer.h> #include <Update.h> WebServer server(80); void setup() { Serial.begin(115200); // 其他初始化逻辑... server.on("/update", HTTP_POST, [](){ Serial.println("收到/update请求"); // 打印所有表单参数名 for (int i=0; i<server.args(); i++) { Serial.printf("参数%d: %s\n", i, server.argName(i).c_str()); } server.sendHeader("Connection", "close"); server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); ESP.restart(); }, [](){ Serial.println("触发上传处理回调"); HTTPUpload& upload = server.upload(); if(upload.status == UPLOAD_FILE_START){ Serial.printf("开始上传: %s\n", upload.filename.c_str()); // 原Update库初始化逻辑... } else if(upload.status == UPLOAD_FILE_WRITE){ // 原写入Flash逻辑... } else if(upload.status == UPLOAD_FILE_END){ // 原完成处理逻辑... } }); server.begin(); } void loop() { server.handleClient(); }
内容的提问来源于stack exchange,提问作者exMechCoder
相关产品推荐
相关产品推荐

