STM32基于mbedTLS向Firebase发PUT请求返回400,JSON构造求助
环境与现状
- 基于STM32,结合mbedTLS、LwIP和FreeRTOS实现Firebase Database安全HTTP客户端,用于远程读写传感器数据
- SSL连接正常,GET请求能成功获取数据,但PUT请求返回400 Bad Request,服务器提示
No data supplied
GET请求正常示例
. Verifying peer X.509 certificate... ok
Write to server: 169 bytes written
GET /Command/TV1.json?auth=[DATABASE SECRET] HTTP/1.1
Host: ecu.firebaseio.com
Content-lenght: 0
Connection: Close< Read from server: 303 bytes read
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 23 Sep 2024 06:39:28 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 16
Connection: close
Access-Control-Allow-Origin: *
Cache-Control: no-cache
Strict-Transport-Security: max-age=31556926; includeSubDomains; preload{"Status":"OFF"}
GET请求代码:
strcpy(path, "/LAB/Temperatures.json?auth=[Database Secret]"); len = sprintf((char*) buf, "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "Content-lenght: 0\r\n" "Connection: Close\r\n\r\n", path, SERVER_NAME); while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) { if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret); goto exit; } }
PUT请求错误示例
. Setting up the SSL/TLS structure... ok
. Connecting to ecu.firebaseio.com at port: 443 ... ok
. Performing the SSL/TLS handshake... ok
. Verifying peer X.509 certificate... ok
return (<Write to server: 272 bytes written PUT /LAB/Temperatures.json?auth=[DATABASE SECRET] HTTP/1.1 Host: ecu.firebaseio.com Content-Type: application/json Content-Lenght: 75 {"Enclosure Temperatures" : "23.15", "MCU Temperatures" : "29.00"} < Read from server: 337 bytes read HTTP/1.1 400 Bad Request Server: nginx Date: Mon, 23 Sep 2024 06:39:12 GMT Content-Type: application/json; charset=utf-8 Content-Length: 36 Connection: keep-alive Access-Control-Allow-Origin: * Cache-Control: no-cache Strict-Transport-Security: max-age=31556926; includeSubDomains; preload { "error" : "No data supplied." } 368 bytes read HTTP/1.1 400 Bad Request Server: nginx Date: Mon, 23 Sep 2024 06:39:12 GMT Content-Type: text/html Content-Length: 150 Connection: close Strict-Transport-Security: max-age=31556926; includeSubDomains; preload <html> <head><title>400 Bad Request</title></head> <body> <center><h1>400 Bad Request</h1></center> <hr><center>nginx</center> </body> </html> ../Middlewares/Third_Party/mbedTLS/source/ssl_msg.c:4681: mbedtls_ssl_fetch_input() returned -29312 (-0x7280) ../Middlewares/Third_Party/mbedTLS/source/ssl_msg.c:4046: ssl_get_next_record() returned -29312 (-0x7280) EOF )
PUT请求代码:
sprintf(stringToProcess,"{\"Enclosure Temperatures\" : \"%.2f\", \"MCU Temperatures\" : \"%.2f\"}", enclosure_temp, mcu_temp); strcpy(path, "/LAB/Temperatures.json?auth=[Database Secret]"); len = snprintf((char*) buf, sizeof(buf) -1, "PUT %s HTTP/1.1\r\n" "Host: %s\r\n" "Content-Type: application/json\r\n" "Content-Lenght: %d\r\n" "\r\n" "%s\r\n", path, SERVER_NAME, strlen(stringToProcess), stringToProcess); while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) { if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret); goto exit; } }
问题根源与修复方案
1. HTTP头拼写错误
代码中Content-lenght是拼写错误,正确应为Content-Length(大写L,末尾为th而非ht)。这个错误会导致服务器无法识别请求体长度,进而判定无数据传入。
2. 请求体末尾多余换行符
PUT请求构造时,JSON后额外添加的\r\n会被计入请求体长度,但Content-Length计算的是JSON本身的长度,导致长度不匹配。需去掉该多余换行。
修复后的PUT请求代码
sprintf(stringToProcess,"{\"Enclosure Temperatures\" : \"%.2f\", \"MCU Temperatures\" : \"%.2f\"}", enclosure_temp, mcu_temp); strcpy(path, "/LAB/Temperatures.json?auth=[Database Secret]"); // 修复Content-Length拼写,移除JSON末尾的\r\n len = snprintf((char*) buf, sizeof(buf) -1, "PUT %s HTTP/1.1\r\n" "Host: %s\r\n" "Content-Type: application/json\r\n" "Content-Length: %d\r\n" "\r\n" "%s", path, SERVER_NAME, strlen(stringToProcess), stringToProcess); while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) { if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret); goto exit; } }
额外验证建议
- 打印构造后的
buf内容,与Python请求的原始数据包对比,确保HTTP头和请求体完全一致 - 确认
strlen(stringToProcess)计算的长度准确,无额外空白字符
内容的提问来源于stack exchange,提问作者l.g.oasis

