ESP 32 не удалось подключиться к сайту https и вернуть данные с помощью GET

Я создал ThingHTTP ниже:

https://api.thingspeak.com/apps/thinghttp/send_request?api_key=BVLJ7A6KNK9VVAYK

В моем браузере я мог видеть ответ. Но я не могу заставить это работать в моем ESP32. Я понимаю, что это https, поэтому мне придется объявить данные корневого сертификата. Я попытался изменить на основе этого урока:

https://github.com/witnessmenow/arduino-sample-api-request/blob/master/ESP8266/HTTP_GET/HTTP_GET.ino

Мой код выглядит следующим образом:

#include <WiFi.h>
#include <WiFiClientSecure.h>

// - - - - - - - Замените следующее! ------
char ssid[] = "SSID";       // SSID вашей сети (имя)
char password[] = "pass";  // ваш сетевой пароль

// Для запросов, не связанных с HTTPS
// Уважаемый клиент;

// Для HTTPS-запросов
WiFiClientSecure client;


// Только база URL-адреса, к которому вы хотите подключиться
#define TEST_HOST "https://api.thingspeak.com/apps/thinghttp/send_request?api_key=BVLJ7A6KNK9VVAYK"


const char *server_cert = "-----BEGIN CERTIFICATE-----\n"
                                  "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\n"
                                  "RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\n"
                                  "VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\n"
                                  "DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\n"
                                  "ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\n"
                                  "VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\n"
                                  "mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\n"
                                  "IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\n"
                                  "mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\n"
                                  "XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\n"
                                  "dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\n"
                                  "jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\n"
                                  "BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\n"
                                  "DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\n"
                                  "9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n"
                                  "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\n"
                                  "Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\n"
                                  "ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\n"
                                  "R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n"
                                  "-----END CERTIFICATE-----\n";


void setup() {

  Serial.begin(115200);

  // Connect to the WiFI
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  //--------

  // Checking the cert is the best way on an ESP32
  // This will verify the server is trusted.
  client.setCACert(server_cert);

  // If you don't want to verify the server
  // Unlike the fingerprint method of the ESP8266 which expires frequently
  // the cert lasts years, so I don't see much reason to ever
  // use this on the ESP32
  // client.setInsecure();

  makeHTTPRequest();
}

void makeHTTPRequest() {
  delay(5000);
  // Opening connection to server (Use 80 as port if HTTP)
  if (!client.connect(TEST_HOST, 443))
  {
    Serial.println(F("Connection failed"));
    return;
  }

  // give the esp a breather
  yield();
  client.connect(TEST_HOST, 443);
  // Send HTTP request
  client.print(F("GET "));
  // This is the second half of a request (everything that comes after the base URL)
  client.print(""); // %2C == ,
  client.println(F(" HTTP/1.1"));

  //Headers
  client.print(F("Host: "));
  client.println(TEST_HOST);

  client.println(F("Cache-Control: no-cache"));

  if (client.println() == 0)
  {
    Serial.println(F("Failed to send request"));
    return;
  }
  //delay(100);
  // Check HTTP status
  char status[32] = {0};
  client.readBytesUntil('\r', status, sizeof(status));
  if (strcmp(status, "HTTP/1.1 200 OK") != 0)
  {
    Serial.print(F("Unexpected response: "));
    Serial.println(status);
    return;
  }

  // Skip HTTP headers
  char endOfHeaders[] = "\r\n\r\n";
  if (!client.find(endOfHeaders))
  {
    Serial.println(F("Invalid response"));
    return;
  }

  // This is probably not needed for most, but I had issues
  // with the Tindie api where sometimes there were random
  // characters coming back before the body of the response.
  // This will cause no hard to leave it in
  // peek() will look at the character, but not take it off the queue
  while (client.available() && client.peek() != '{')
  {
    char c = 0;
    client.readBytes(&c, 1);
    Serial.print(c);
    Serial.println("BAD");
  }

  // While the client is still availble read each
  // byte and print to the serial monitor
  while (client.available()) {
    char c = 0;
    client.readBytes(&c, 1);
    Serial.print(c);
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

программа смогла скомпилироваться и могла работать до тех пор, пока не будет показано, что она подключена к сети. Но затем он вернул "Соединение не удалось!" Я полагаю, что он застрял на этой строке :

if (!client.connect(TEST_HOST, 443))

Я не уверен, в чем здесь проблема. Комментарии приветствуются.

, 👍0

Обсуждение

Попробуйте создать правильно отформатированный HTTP-запрос. Попробуйте также подключиться к серверу, а не к веб-странице. В вашем запросе на получение так много ошибок, что я не знаю, с чего начать..., @Majenko


2 ответа


Лучший ответ:

1

Что - то не так с вашим запросом GET (которые не имеют ничего общего с Arduino-просто изучите основы протокола, который вы пытаетесь использовать, прежде чем использовать его):

  • Вы пытаетесь открыть сокет по URL-адресу, а не по серверу. Это никогда не сработает. Вместо этого подключитесь к серверу (подсказка: сервер или "ПОЛНОЕ доменное имя" - это бит между https:// и следующим /).
  • Вы не указываете никакого пути в своем запросе GET, только комментарий, в котором говорится, что вы должны предоставить. Подсказка: путь-это все, что следует после (и включая) / после полного доменного имени.
  • Ваш заголовок Host: должен содержать только полное доменное имя, а не весь URL-адрес. К настоящему времени вы уже должны знать, что такое полное доменное имя.
  • Вы также должны включить соединение: закройте в заголовках, чтобы сообщить серверу, что вы не будете держать сокет открытым.

Исправьте эти проблемы, и вы, возможно, начнете видеть, как происходит что-то полезное.

,

Спасибо за советы. Был новичком в этом деле. Наверное, я начал не с того места. Во всяком случае, после реализации того, что вы сказали, и других незначительных ошибок, похоже, это работает. Я узнал, что мне нужно изменить сертификаты для веб-сайта, их несколько типов. В любом случае, еще раз спасибо., @sam


-1

Приведенный ниже фрагмент кода взят из кода прошивки, которую я недавно программировал для использования на микроконтроллерах Tensilica, совместимых с Xtensa LX6/7 (ESP32). В приведенном ниже коде выполняется HTTPS-запрос с использованием библиотеки WIFIClientsecure.

String GetInfoFromDataverse(String url) {
  //Проверяем статус соединения WiFi
    
  if(WiFi.status() != WL_CONNECTED){
    mserial.printStrln("WiFi Disconnected");
    if (connect2WIFInetowrk()){
      GetInfoFromDataverse(url);
    }
  }
            
  int str_len = SERVER_URL.length() + 1; // Длина (с одним дополнительным символом нулевого терминатора)
  char SERVER_URL_char [str_len];    // Подготавливаем массив символов (буфер)
  SERVER_URL.toCharArray(SERVER_URL_char, str_len);    // Копируем его
    
  client.stop();
  client.setCACert(HARVARD_ROOT_CA_RSA_SHA1);
    
  if (!client.connect(SERVER_URL_char, SERVER_PORT)) {
      mserial.printStrln("Cloud server URL connection FAILED!");
      mserial.printStrln(SERVER_URL_char);
      int server_status = client.connected();
      mserial.printStrln("Server status code: " + String(server_status));
      return "";
  }
  
  mserial.printStrln("Connected to the dataverse of Harvard University"); 
  mserial.printStrln("");
  
  // Теперь мы создаем URI для запроса
  mserial.printStr("Requesting URL: ");
  mserial.printStrln(url);

  // Делаем HTTP-запрос и добавляем HTTP-заголовки
  // заголовок сообщения
  String postHeader = "GET https://" + SERVER_URL + URL + " HTTP/1.1\r\n";
  postHeader += "Host: " + SERVER_URL + ":" + String(SERVER_PORT) + "\r\n";
  //postHeader += "X-Dataverse-key: " + API_TOKEN + "\r\n";
  postHeader += "Content-Type: text/json\r\n";
  postHeader += "Accept: text/html,application/xhtml+xml,application/xml,application/json,text/json;q=0.9,*/*;q=0.8\r\n";
  postHeader += "Accept-Encoding: gzip,deflate\r\n";
  postHeader += "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n";
  postHeader += "User-Agent: AeonLabs LDAD Smart DAQ device\r\n";
  postHeader += "Keep-Alive: 300\r\n";
  postHeader += "Connection: keep-alive\r\n";
  postHeader += "Accept-Language: en-us\r\n";

  // хвост запроса
  String tail = "\r\n--" + boundary + "--\r\n\r\n";

  // длина содержимого
  int contentLength = tail.length();
  postHeader += "Content-Length: " + String(contentLength, DEC) + "\n\n";
  
  // отправляем заголовок поста
  int postHeader_len=postHeader.length() + 1; 
  char charBuf0[postHeader_len];
  postHeader.toCharArray(charBuf0, postHeader_len);
  client.print(charBuf0);
  
  mserial.printStrln("======= Headers =======");
  mserial.printStrln(charBuf0);
  mserial.printStrln("======= End of Headers =======");
  
  // Читаем все строки ответа с сервера и печатаем их в mserial
  String responseHeaders = "";

  mserial.printStr("Waiting for server response...");
  long timeout= millis();
  long ttl=millis()-timeout;
  while (client.connected() && abs(ttl) < 30000) { // 30 сек.
    ttl=millis()-timeout;      
    responseHeaders = client.readStringUntil('\n');
    if (responseHeaders == "\r") {
      break;
    }
  }
  if (abs(ttl) < 30000){
    mserial.printStrln("OK");
  }else{
    mserial.printStrln("timed out.");  
  }
  
  String responseContent = client.readStringUntil('\n');
  client.stop();

  return responseContent;
  }
,