Веб-сервер Arduino POST получает переменные

Я научился считывать данные более низкого уровня при общении в Интернете. В рамках большого проекта я тестирую веб-интерфейс.
До сих пор я мог отобразить основной веб-сайт и, увидев веб-адрес, прочитать данные из запроса GET.
Поскольку я собираюсь отправлять коды, я хочу использовать метод POST.
Я пытаюсь сделать это отдельным классом для своих будущих проектов, поэтому я отправляю только сам метод класса. (Позже он будет принимать содержимое веб-сайтов в виде строки, но сейчас входные переменные еще не реализованы)
Я использую esp8266, но предпочел бы избегать конкретных библиотек esp8266, поскольку я хочу, чтобы он в конечном итоге работал на эквиваленте Realtek.
Код:

uint8_t Stranky::Stav(String obsahStranky, uint8_t obnovovat){
    WiFiClient client = server.available();
  if (client) {
    // HTTP-запрос заканчивается пустой строкой
    char vstupRiadok[150]={'\0'};
    uint8_t i=0;
    bool currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        vstupRiadok[i]=c;
        if(c=='\n' || i>=149) {
            Serial.println(vstupRiadok);
            //------------Извлекаем сюда переменные--------
            for(uint8_t j=0; j<149; j++) {
                //Serial.print(vstupRiadok[j]);
                vstupRiadok[j]='\0';
            }
            i=0;
        } else i++;
        if (c == '\n' && currentLineIsBlank) {
            Serial.println("Sending page");
            client.println(ohlasSa(1,1));
            client.println("<!DOCTYPE HTML>");
          // отправляем стандартный HTTP-заголовок ответа
            client.println("<html><head> <meta charset=\"utf-8\"></head><body>");
            client.println("<h1> Nic nove</h1>");
            client.println("<form method='POST'>");
            client.println("Name:<input type=\"text\" id=\"Name\" name=\"Name\"/><br>\nSurname:<input type=\"text\" id=\"Surname\" name=\"Surname\"><br>\n<input type=\"submit\" value=\"Submit\"/><input   type='reset'/>  </form> </body>");
            client.println("</html>");
          break;
        }
        if (c == '\n') {
          // вы начинаете новую строку
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // вы получили символ в текущей строке
          currentLineIsBlank = false;
        }
      }
    }
    // дать веб-браузеру время для получения данных
    delay(1);

    // закрыть соединение:
    client.stop();
    Serial.println("Prehliadač dpojený");
  }
}

В результате получается код браузера:

<!DOCTYPE HTML>
<html><head> <meta charset="utf-8"></head><body>
<h1> Nic nove</h1>
<form method='POST'>
   Name:<input type="text" id="Name" name="Name"/><br>
   Surname<input type="text" id="Surname" name="Surname"><br>
<input type="submit" value="Submit"/><input type='reset'/>  </form> </body>
</html>

Когда я отправляю какие-либо данные через форму, они не принимаются, а получаются только следующие:

WS:ac
:ref 1
WS:av
:ref 2
:ur 2
:rn 469
POST / HTTP/1.1

Host: 192.168.43.209

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: sk,cs;q=0.8,ru;q=0.6,en;q=0.4,en-US;q=0.2

Accept-Encoding: gzip, deflate

Referer: http://192.168.43.209/

Content-Type: application/x-www-form-urlencoded

Content-Length: 25

Connection: keep-alive

Upgrade-Insecure-Requests: 1



Sending page

Нет сообщений или переменных cookie, которые я мог бы извлечь

Я нахожусь далеко от дома, и у меня слишком мало данных, чтобы устанавливать другие программы, такие как wire-shark, через общий доступ к телефонной сети

, 👍-1

Обсуждение

Я обнаружил, что мне нужно декодировать объект json, но как мне получить его из полученных данных?, @Tomas


2 ответа


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

0

На основе кода дешифровщика я смог объединить его в работающий код
Проблема заключалась в том, что общение начинается с переменных заголовка, затем пустая строка, затем тело, содержащее переменные
Сначала установите соединение: и создайте базовые переменные

uint8_t Stranky::Stav(){
    WiFiClient client = server.available();
  if (client) {
    // HTTP-запрос заканчивается пустой строкой
    bool currentLineIsBlank = 0;
    bool body=0;             // Помогает увидеть, является ли это все еще заголовком
    bool finished=0;         // Чтобы узнать, прерывать ли соединение
    uint8_t i = 0;           // Чтобы итератор не сбрасывался в 0
    char fullLine[81]={'\0'};  // буфер для ввода символа в строку
    // символ *pch;

    Serial.print("User connected\n");
    while (client.connected()) {
        while (client.available()) {
            bool linEnd=0;          // Когда работать со строкой (распечатать ее)

Получить один входящий символ:

            char c = client.read();

Теперь сначала обработайте символ новой строки
Если бы последняя строка была пустой Это бы означало: Заголовок закончен и перемещается в тело входящих данных
Если не изменить currentLineIsBlank (пока новая строка не получит свой первый символ)

 if(c=='\n') {
если (currentLineIsBlank) {
если(!тело) тело=1;
текущаяЛайнИсБланк=0;
} еще {
Серийный. Распечатать("/");
текущаяЛайнИсБланк=1;
ЛинЭнд=1;
}

Теперь давайте рассмотрим любой другой символ, кроме новой строки:

            if(c=='\n') {
                if(currentLineIsBlank) {
                    if(!body) body=1;
                    currentLineIsBlank=0;
                } else {
                    Serial. print("/");
                    currentLineIsBlank=1;
                    linEnd=1;
                }

Убедитесь, что наш массив не переполняется

            } else {
                currentLineIsBlank=0;   //If it has a character then its not empty
                fullLine[i]=c;
                i++;                //Move to the next letter
            }

Теперь, когда мы знаем, что происходит, мы можем предпринять какие-то действия после завершения строки буфера

если мы находимся на стадии тела, но еще не "закончили" отправку кода

            if(i>=81) linEnd=1;

Начать извлечение символов из тела входящих данных.
В простой форме, такой как наша, переменные POST находятся в последней строке, поэтому мы просто продолжим переписывать строку

            if(linEnd){ 
                if(body && !finished) {
                    finished=1;          // Finishing sending page
                    Serial.printf(F("Variables:\n\t"));

Наконец отправьте HTML-код веб-сайта:

                    uint8_t k=0;
                    while (client.available()) {
                        fullLine[k]=client.read();
                        Serial.printf(F("%c"),fullLine[k]);
                        if(k<80) k++;
                        if(fullLine[k]=='\n') {        
                            k=0;
                            Serial.println();
                        }
                    }
                    // Here you can extract variables as shown in codebreakers' answer

Если мы еще не имеем дело с телом:

                    Serial.print("Sending page\n");
                    client.println(heatheRoutine()); //I have extra routine to inject heather so I do not have to write it every time I write a page
                    client.println("<!DOCTYPE HTML>");
                    // send a standard http response header
                    client.println("<html><head> <meta charset=\"utf-8\"></head><body>");
                    client.println("<h1>Fill the form now !!!</h1>");
                    client.println("<form method='POST'>");
                    client.println("Meno:<input type=\"text\" id=\"Name\" name=\"Name\"/><br>\nPriezvisko:<input type=\"text\" id=\"Surname\" name=\"Surname\"><br>\n<input type=\"submit\" value=\"Submit\"/><input    type='reset'/>  </form> </body>");
                    /*Serial.printf(F("Page source send\n"));*/
                    client.println("</html>\n");
                    break;
                }

Если мы закончили то, что хотели, нам нужно выйти из цикла общения

                currentLineIsBlank=1;
                for(uint8_t j=0; j<i; j++) { //Print the last line
                    Serial.print(fullLine[j]);
                    fullLine[j]='/0';     //restore default values To prevent characters leaking into next line
                }
                Serial.println();
                i=0;    //Since we are on an end of a line we are starting from first position in a buffer
            }
        }

И закройте соединение:

        if(finished) {
            Serial.printf(F("Ending\n"));
            break;
        }
    }

Полный код:

    // give the web browser time to receive the data
    delay(1);

    // close the connection:
    client.stop();
    Serial.println("browser disconnected");
  }
}
,

0

Проверьте свое определение

String vstupRiadok

такого быть не должно

String vstupRiadok="                                      "; //80 пробелов

Я бы все равно заменил его фиксированным символом приличного размера

char vstupRiadok[81] = {'\0'};

если вы создаете пустую строку или другой текст, не забудьте написать терминатор конца '\0' и убедитесь, что массив символов равен +1 размеру самой длинной строки

Как класс String сам по себе является проблемой, как класс Arduino.
В созданном HTML-коде отсутствует

<head> <meta charset    ="utf-8"></head>

ошибка в инструментах разработки. Кроме того, какой серверный код работает на Arduino, он не указан. Класс создает html-страницу, но, по крайней мере, в FF75 он пытается вызвать server.ip\odpoved - поэтому для декодирования этого маршрута должен быть какой-то код js или Arduino, поскольку из формы не прикреплены параметры.

EDITПроцедура извлечения будет выглядеть следующим образом:

bool currentLineIsBlank = true;
bool currentLineIsGet = true;
uint8_t tCount = 0;
char tBuf[64];
uint8_t n=0;
uint8_t s=0;
char *pch;

Serial.print("Client request: ");

 while (client.connected()) {
  while (client.available()) {
    char c = client.read();

    if (currentLineIsGet && tCount < 63) {
      tBuf[tCount] = c;
      tCount++;
      tBuf[tCount] = 0;
    }

    if (c == '\n' && currentLineIsBlank) {
      Serial.println(tBuf);
      // получить данные POST
      Serial.print("POST data: ");
      while (client.available()) Serial.write(client.read());
      Serial.println();

      pch = strtok(tBuf, "?");

      while (pch != NULL) {
        if (strncmp(pch, "Name=", 5) == 0) {
          pch = pch+6;
          char Name [24] = {'\0'};
          while(pch != '&'){
             char Name [n] = pch;
             n++;
           }
          char Name [n+1] = {'\0'};
          Serial.print("Name="); Serial.println(Name);
        }

        if (strncmp(pch, "Surname=", 8) == 0) {
          pch=pch+9;
          char Surname[24] = {'\0'};
          while(pch != '\r') {   // проверяем, есть ли это в вашем ответе после содержимого или это '\0'
             char Surname [s] = pch;
             s++;
           }
          char Surname [s+1] = {'\0'};
          Serial.print("Surname="); Serial.println(Surname);
        }
        pch = strtok(NULL, "& ");
      }
  // здесь начинается часть отправки ответа

Для этого вам не нужен синтаксический анализатор JSON, просто получите почтовый запрос

,

Комментарии не для расширенного обсуждения; этот разговор был [перемещен в чат](https://chat.stackexchange.com/rooms/106650/discussion-on-answer-by-codebreaker007-arduino-webserver-post-receive-varriables)., @VE7JRO