You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32向Django服务器发送POST请求失败及视图实现咨询

ESP32 POST请求到ngrok托管的Django服务器返回错误码-1的排查与解决方案

一、错误码-1的核心原因与排查步骤

ESP32 HttpClient库返回错误码-1,本质是TCP连接建立失败,结合ngrok+Django的场景,按以下顺序排查:

  • 先确认ESP32 WiFi连接状态:必须在WiFi.status() == WL_CONNECTED的前提下再发起请求,别上来就发
  • 验证ngrok URL有效性:用浏览器直接访问生成的ngrok地址,能打开Django页面才算正常;如果打不开,检查ngrok是否在运行,本地Django服务是否启动
  • 不要给ngrok URL加端口:ngrok已经把本地端口(比如8000)映射到它的公网域名上,直接用http://xxxx.ngrok.io就行,加:8000会直接报错
  • 关闭ESP32的代理配置:如果之前设过client.setProxy(),直接删掉,代理会阻断公网连接
  • 检查Django的跨域与主机限制:
    • 测试阶段把ALLOWED_HOSTS = ['*']加到settings.py,避免ngrok请求被拦截
    • 装django-cors-headers并配置CORS_ALLOW_ALL_ORIGINS = True,防止跨域拦截

二、ngrok端口的正确用法

ngrok的核心是端口映射,举个例子:

  • 本地Django跑在127.0.0.1:8000,启动ngrok的命令是ngrok http 8000
  • 生成的公网地址类似http://abc123-45-67-89-01.ngrok.io,直接用这个地址访问,不需要加任何端口
  • ngrok会自动把这个域名的HTTP请求(默认80端口)转发到你本地的8000端口

三、处理ESP32 POST请求的Django视图示例

假设ESP32发送JSON格式的传感器数据,视图这么写:

# views.py
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json

# 测试阶段关闭CSRF验证,上线后换CSRF白名单或Token验证
@csrf_exempt
def receive_sensor_data(request):
    if request.method != 'POST':
        return JsonResponse({'status': 'error', 'msg': '只接受POST请求'}, status=405)
    
    try:
        # 解析ESP32发送的JSON数据
        sensor_data = json.loads(request.body)
        # 这里写数据入库逻辑,比如存到Model里
        # from .models import SensorRecord
        # SensorRecord.objects.create(temp=sensor_data['temp'], hum=sensor_data['hum'])
        return JsonResponse({'status': 'success', 'msg': '数据已接收'}, status=200)
    except json.JSONDecodeError:
        return JsonResponse({'status': 'error', 'msg': '数据格式错误,需JSON'}, status=400)

然后在urls.py配置路由:

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('api/sensor-data/', views.receive_sensor_data, name='sensor_data'),
]

四、ESP32代码修正要点

原代码大概率是URL或请求头的问题,修正后的示例:

#include <WiFi.h>
#include <HttpClient.h>

const char* WIFI_SSID = "你的WiFi名称";
const char* WIFI_PWD = "你的WiFi密码";
// 替换成你的ngrok地址+路由
const char* SERVER_URL = "http://abc123.ngrok.io/api/sensor-data/";

WiFiClient wifiClient;
HttpClient client(wifiClient);

void setup() {
  Serial.begin(9600);
  // 确保WiFi连接成功
  WiFi.begin(WIFI_SSID, WIFI_PWD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi已连接");
}

void loop() {
  // 读取Arduino Uno传来的串口数据
  if (Serial.available() > 0) {
    String rawData = Serial.readStringUntil('\n');
    Serial.print("收到Uno数据:");
    Serial.println(rawData);

    // 构造JSON格式数据(根据你的rawData格式解析,这里是示例)
    String jsonData = "{\"temp\":26.5,\"hum\":62}";

    // 发送POST请求
    client.beginRequest();
    client.post(SERVER_URL);
    // 必须设置Content-Type,否则Django解析不了
    client.sendHeader("Content-Type", "application/json");
    client.sendHeader("Content-Length", String(jsonData.length()));
    client.beginBody();
    client.print(jsonData);
    client.endRequest();

    // 打印响应信息排查问题
    int statusCode = client.responseStatusCode();
    String response = client.responseBody();
    Serial.print("响应状态码:");
    Serial.println(statusCode);
    Serial.print("响应内容:");
    Serial.println(response);

    if (statusCode == -1) {
      Serial.println("连接失败!检查WiFi、SERVER_URL是否正确,ngrok是否在运行");
    }
  }
  delay(3000);
}

关键修正:

  • 先等WiFi连接成功再发请求
  • 正确设置Content-Type: application/json请求头
  • 直接用不带端口的ngrok URL
  • 增加响应打印,方便定位问题

五、Ethernet Shield替代方案的注意事项

如果换用Ethernet Shield,逻辑和ESP32一致,注意两点:

  • 确保Shield获取到有效IP(用Ethernet.localIP()打印确认)
  • 同样直接使用ngrok的公网URL,不要加本地端口

内容的提问来源于stack exchange,提问作者Nolulamo Tshuma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 04:33:14