我正在尝试将 HTTP 请求存储为全局变量。我的软件是关于连接 WiFi 的,我使用的 WiFi 库是基于事件的,这意味着我必须将 HTTP 请求存储在某个地方并等待事件回调。 问题:我再次尝试访问它后,程序崩溃了。日志:
> Guru Meditation Error: Core 0 panic'ed (StoreProhibited). Exception
> was unhandled.
>
> Core 0 register dump: PC : 0x400ff5e5 PS : 0x00060430 A0
> : 0x800d79a1 A1 : 0x3ffbdf90
> --- 0x400ff5e5: httpd_resp_send at F:/Espressif/frameworks/esp-idf-v5.2.5/components/esp_http_server/src/httpd_txrx.c:248
>
> A2 : 0x3ffc93c8 A3 : 0x3f4038ec A4 : 0x00000003 A5
> : 0x00000000 A6 : 0x00000000 A7 : 0x3ffc93c8 A8 :
> 0x00000000 A9 : 0x3ffbdf30 A10 : 0x000001f4 A11 :
> 0x3ffbdf30 A12 : 0x3ffbde44 A13 : 0x3ffbde0c A14 :
> 0x3ffbde20 A15 : 0x3ffbdff0 SAR : 0x00000004 EXCCAUSE:
> 0x0000001d EXCVADDR: 0x00000218 LBEG : 0x400014fd LEND :
> 0x4000150d LCOUNT : 0xffffffff
> --- 0x400014fd: strlen in ROM
> --- 0x4000150d: strlen in ROM
>
>
>
> Backtrace: 0x400ff5e2:0x3ffbdf90 0x400d799e:0x3ffbdfd0
> 0x400d773b:0x3ffbdff0 0x400d7ad1:0x3ffbe020 0x4016387d:0x3ffbe050
> 0x401633c6:0x3ffbe080 0x401634a1:0x3ffbe0c0 0x4008a129:0x3ffbe0e0
> --- 0x400ff5e2: httpd_resp_send at F:/Espressif/frameworks/esp-idf-v5.2.5/components/esp_http_server/src/httpd_txrx.c:248
> --- 0x400d799e: wifi_setup_handle_response at F:/Documents/dashboardfordevice/device-software/main/wifi_setup_webpage.c:44
> --- 0x400d773b: disconnect_handler at F:/Documents/dashboardfordevice/device-software/main/wifi_manager.c:20
> --- 0x400d7ad1: run_on_event at F:/Documents/dashboardfordevice/device-software/main/wifi.c:32
> --- 0x4016387d: handler_execute at F:/Espressif/frameworks/esp-idf-v5.2.5/components/esp_event/esp_event.c:137
> --- 0x401633c6: esp_event_loop_run at F:/Espressif/frameworks/esp-idf-v5.2.5/components/esp_event/esp_event.c:593
> --- 0x401634a1: esp_event_loop_run_task at F:/Espressif/frameworks/esp-idf-v5.2.5/components/esp_event/esp_event.c:107
> --- 0x4008a129: vPortTaskWrapper at F:/Espressif/frameworks/esp-idf-v5.2.5/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:13
据我了解,这首先是由空字符串引起的,但这是 wifi_setup_webpage.c 中的第 44 行,httpd_resp_send(request, "200", 3);
据我所知,这不可能是问题所在,因为执行同样事情的其他处理程序不会崩溃,唯一的区别是它们指向请求的指针是“新鲜的”。
我使用全局变量存储请求:httpd_req_t* request;
然后使用request = req;
该方法的完整代码对其进行分配:
esp_err_t connect_post_handler(httpd_req_t *req)
{
size_t size = req->content_len;
if (size > 1024) {
// too big
const char* response = "Content too massive, but you know what else is massive?";
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, response);
return ESP_OK;
}
char content[1024];
int bytes_read = httpd_req_recv(req, content, size);
if (bytes_read == 0) {
// connection closed
return ESP_ERR_HTTPD_INVALID_REQ;
}
cJSON* jsonData = cJSON_ParseWithLength(content, size);
if (jsonData == NULL) {
// json parsing failed, bad request
const char* response = "Bad JSON format";
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, response);
return ESP_OK;
}
char* ssid = cJSON_GetObjectItem(jsonData, "ssid")->valuestring;
char* password = cJSON_GetObjectItem(jsonData, "password")->valuestring;
cJSON_Delete(jsonData);
request = req;
reconnect_callback(ssid, password);
return ESP_OK;
}
以及发送请求的方法的完整代码:
void wifi_setup_handle_response(bool boolean, const char * response)
{
// cJSON* response_data = cJSON_CreateObject();
// cJSON_AddBoolToObject(response_data, "success", boolean);
// cJSON_AddStringToObject(response_data, "message", response);
// char* response_string = cJSON_Print(response_data);
// ESP_LOGI(LOG_TAG, "Raw Response: %s", response_string);
// if (response_string == NULL) {
// // failed
// ESP_LOGE(LOG_TAG, "Could not write wifi connect response to string");
// httpd_resp_send_500(request);
// cJSON_Delete(response_data);
// return;
// }
if (request == NULL) {
ESP_LOGE(LOG_TAG, "request is null, aha!");
return;
}
httpd_resp_send(request, "200", 3);
// free(response_string);
// cJSON_Delete(response_data);
}
仅供参考:这两个函数之间有大约 3 秒的间隔。顺序:connect_post_handler 然后 void wifi_setup_handle_response。我认为这是因为与堆栈内存相关的某些东西被破坏了,然后指向它的指针不再有效,但我不知道如何处理它,因为请求 typedef 有很多指向其他内容的奇特指针。
HTTP 请求实例仅在请求处理程序回调返回之前有效。
如果您想在处理程序回调之外使用请求实例,则应使用httpd_req_async_handler_begin()复制请求,以便随后在其他地方使用。当不再需要时,请调用httpd_req_async_handler_complete()删除副本。
另请参阅https://github.com/espressif/esp-idf/tree/v5.4.1/examples/protocols/http_server/async_handlers