ESP32-CAM使用WiFiClientSecure连接Azure服务器失败求助
ESP32-CAM 无法连接 Azure 认知服务 443 端口的排查与解决
核心问题分析
你的代码使用WiFiClientSecure发起TLS连接,但ESP32-CAM默认没有预装Azure认知服务域名对应的根证书,同时TLS连接依赖正确的系统时间,这两个因素是导致连接失败的最常见原因。
具体排查步骤与修复方案
1. 处理TLS证书验证
WiFiClientSecure默认会验证服务器证书,ESP32如果没有对应根证书,会直接拒绝连接。有两种处理方式:
- 方式一:添加正确的根证书(生产环境推荐)
访问Azure认知服务域名myproject.cognitiveservices.azure.com,获取其SSL证书链中的根证书(如DigiCert Global Root CA),将证书内容以字符串形式添加到代码中,通过client.setCACert()设置:const char* azure_root_ca = R"EOF( -----BEGIN CERTIFICATE----- // 粘贴实际获取的根证书内容 -----END CERTIFICATE----- )EOF"; void setup() { // ... WiFi连接代码 ... client.setCACert(azure_root_ca); // 添加证书配置 Serial.printf("Connecting to %s:%d... ", host, Port); if (!client.connect(host, Port)) { Serial.println("Failure in connection with the server"); Serial.print("Error code: "); Serial.println(client.lastError()); // 打印错误码辅助排查 } else { Serial.println("Connected successfully!"); } } - 方式二:临时跳过证书验证(仅测试用)
如果只是测试连接,可以关闭证书验证,快速确认是否是证书问题:void setup() { // ... WiFi连接代码 ... client.setInsecure(); // 关闭证书验证 // ... 连接代码 ... }
2. 同步系统时间
TLS连接需要ESP32有正确的当前时间,否则证书有效期验证会失败。添加NTP时间同步代码:
#include <NTPClient.h> #include <WiFiUdp.h> WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "pool.ntp.org", 8*3600, 60000); // 东八区时间配置 void setup() { // ... WiFi连接代码 ... timeClient.begin(); while(!timeClient.update()) { timeClient.forceUpdate(); delay(1000); Serial.println("Syncing time..."); } Serial.print("Current time: "); Serial.println(timeClient.getFormattedTime()); // ... 后续连接代码 ... }
3. 排查网络环境问题
- 确认ESP32-CAM连接的WiFi与笔记本处于同一网络,且网络没有限制出站443端口的防火墙规则
- 手动测试ESP32的DNS解析是否正常,添加代码打印解析后的IP:
IPAddress ip; if(WiFi.hostByName(host, ip)){ Serial.print("Resolved IP: "); Serial.println(ip.toString()); } else { Serial.println("DNS resolution failed"); }
4. 打印详细错误信息
在连接失败时,打印WiFiClientSecure的错误码和错误信息,帮助定位具体问题:
if (!client.connect(host, Port)) { Serial.println("Failure in connection with the server"); Serial.print("Error code: "); Serial.println(client.lastError()); Serial.print("Error message: "); Serial.println(client.lastErrorMsg()); }
修复后的完整示例代码
#include "esp_camera.h" #include <WiFi.h> #include <WiFiClientSecure.h> #include <NTPClient.h> #include <WiFiUdp.h> // WiFi credentials const char* ssid = "mywifiId"; const char* password = "MyPass"; WiFiClientSecure client; const char* host = "myproject.cognitiveservices.azure.com"; const int Port = 443; // Azure根证书示例(请替换为实际获取的根证书) const char* azure_root_ca = R"EOF( -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- )EOF"; WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "pool.ntp.org", 8*3600, 60000); void setup() { Serial.begin(115200); // Connect to WiFi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("WiFi connected."); // Sync time timeClient.begin(); while(!timeClient.update()) { timeClient.forceUpdate(); delay(1000); Serial.println("Syncing time..."); } Serial.print("Current time: "); Serial.println(timeClient.getFormattedTime()); // Set root certificate client.setCACert(azure_root_ca); // DNS resolution test IPAddress ip; if(WiFi.hostByName(host, ip)){ Serial.print("Resolved IP for "); Serial.print(host); Serial.print(": "); Serial.println(ip.toString()); } else { Serial.println("DNS resolution failed for " + String(host)); } // Connect to server Serial.printf("Connecting to %s:%d... ", host, Port); if (!client.connect(host, Port)) { Serial.println("Failure in connection with the server"); Serial.print("Error code: "); Serial.println(client.lastError()); Serial.print("Error message: "); Serial.println(client.lastErrorMsg()); } else { Serial.println("Connected successfully!"); } } void loop() { }
内容的提问来源于stack exchange,提问作者Hassan Ali
相关产品推荐
相关产品推荐

