ESP32作为AP接收POST请求触发panic重启及JSON传参问题求助
ESP32 AP模式POST请求崩溃问题排查与JSON传输实现
一、POST请求触发panic重启的排查步骤
- 优先抓取串口崩溃日志:ESP32触发panic时会通过串口输出错误详情,将串口波特率设为115200,抓取崩溃时的
Guru Meditation Error错误码,最常见的错误原因为非法内存访问、栈溢出、堆越界,可直接定位问题方向。 - 检查AsyncWebServer POST回调写法:
绝大多数崩溃都是因为未正确处理POST请求体,SPAsyncWebServer不能直接在主回调中调用
request->content()读取全量数据,请求体超过默认buffer大小时会直接触发内存越界,必须注册onBody回调分段接收数据。 - 检查参数解析的边界处理:如果使用
strcpy、sscanf等无边界校验的函数解析字符串,或者未限制输入长度,下发的WiFi凭证超出buffer大小时会触发栈溢出。需提前校验:SSID最长32字符、WiFi密码最长64字符,超出阈值直接返回错误,不进入后续处理逻辑。 - 检查内存占用:POST处理过程中如果频繁使用
String类拼接字符串、申请动态内存未释放,会导致堆内存不足或碎片化,可在回调前后打印ESP.getFreeHeap()的返回值,排查内存泄漏问题。 - 检查WiFi连接逻辑:如果在AsyncWebServer的回调中直接执行
WiFi.begin()切换STA模式,会和正在运行的WebServer服务产生资源冲突,直接触发崩溃。正确做法是在POST回调中仅将凭证存储到全局变量、标记连接标志位,在loop()函数中异步执行WiFi连接逻辑,不要在WebServer回调中执行任何阻塞/修改网络状态的操作。
二、JSON格式数据传输实现
ESP32侧实现
首先安装ArduinoJson库,参考代码如下:
#include <ArduinoJson.h> #include <ESPAsyncWebServer.h> // 全局变量存储WiFi凭证和连接标志 char global_ssid[33] = {0}; char global_pwd[65] = {0}; uint8_t wifi_connect_flag = 0; String post_body; AsyncWebServer server(80); void setup(){ // 省略AP初始化、串口初始化代码 server.on("/setWiFi", HTTP_POST, [](AsyncWebServerRequest *request){ // 全量body接收完成后处理 if(post_body.length() > 0){ StaticJsonDocument<256> doc; DeserializationError err = deserializeJson(doc, post_body); if(err){ request->send(400, "application/json", "{\"code\":400,\"msg\":\"JSON格式错误\"}"); }else{ const char* recv_ssid = doc["ssid"]; const char* recv_pwd = doc["pwd"]; strncpy(global_ssid, recv_ssid, sizeof(global_ssid)-1); strncpy(global_pwd, recv_pwd, sizeof(global_pwd)-1); wifi_connect_flag = 1; request->send(200, "application/json", "{\"code\":200,\"msg\":\"凭证接收成功\"}"); } post_body.clear(); }else{ request->send(400, "application/json", "{\"code\":400,\"msg\":\"请求体为空\"}"); } }, NULL, [](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){ // 分段接收请求体 if(!index){ post_body.clear(); // 提前拦截过大的请求体,避免内存溢出 if(total > 256){ request->send(413, "application/json", "{\"code\":413,\"msg\":\"请求体过大\"}"); return; } } for(size_t i=0; i<len; i++){ post_body += (char)data[i]; } }); server.begin(); } void loop(){ // 异步执行WiFi连接 if(wifi_connect_flag == 1){ wifi_connect_flag = 0; WiFi.begin(global_ssid, global_pwd); // 省略WiFi连接状态判断逻辑 } }
Python侧请求代码
import requests # ESP32 AP模式默认IP为192.168.4.1 ESP_AP_IP = "192.168.4.1" wifi_config = { "ssid": "待接入的WiFi名称", "pwd": "待接入的WiFi密码" } try: response = requests.post(f"http://{ESP_AP_IP}/setWiFi", json=wifi_config, timeout=5) response.raise_for_status() print("下发成功:", response.json()) except Exception as e: print("请求失败:", str(e))
内容的提问来源于stack exchange,提问作者JoshFuller
相关产品推荐
相关产品推荐

