ESP32 IDF development application? http request

ESP32 IDF development application? http request

    • 1. The blogger’s purpose for writing this technical article:
    • 2. Overview
    • 3. HTTP request
    • 4. HTTP response
    • 6. HTTP response status code
    • 7. Introduction to related APIs
    • 8. Software design
    • 9. Example
    • 10. Debugging results


Don’t get lost-Navigation bar
Quickly navigate to find what you want (article directory)


If this article is useful to you, please like and save it. Your support is the motivation for the blogger to persist.

1. The blogger’s purpose of writing this technical article:

(1) Understand what http is;
(2) How to use http API;
(2), http programming method;

2. Overview

In the previous chapter we have said that http is a transmission protocol based on tcp or above:
(1), definition of http protocol:
http (Hypertext transfer protocol) is a hypertext transfer protocol that provides regulations for data interaction between browsers and servers and the transmission of hypertext (text, pictures, videos, etc.). In other words, the http protocol stipulates the rules to be followed by hypertext transmission.
(2) Characteristics of HTTP protocol:
·Stateless: The HTTP protocol is stateless. There is no memory for transaction processing. If the previous information needs to be processed, it must be retransmitted, which may increase the amount of data transmitted per connection.
· Based on TCP protocol: The purpose of HTTP protocol is to specify the format and data interaction behavior of client and server data transmission, and is not responsible for the details of data transmission. The bottom layer is implemented based on TCP. The version currently in use uses a persistent connection by default, that is, multiple HTTP requests use one TCP connection.
·Simple and fast: When the client requests services from the server, it only needs to transmit the request method and path. The simplicity of the HTTP protocol makes the program size of the HTTP server small and therefore the communication speed is fast;

3. HTTP request

The client sends an HTTP request to the server. The request information includes the following format:?
· request line
· Request header
· Request entity data (request body)

4. HTTP response


HTTP/1.1 200 OK
Date: Tue, 12 Jul 2016 21:36:12 GMT
Content-Length: 563
Content-Type: text/html

Hello http! Simply put, the response message consists of a status line, a response header field (response header), and a response entity. The first line is the status line, which in turn contains the HTTP version, status code, and status phrase; in A carriage return and line feed is followed by the response header, which is also in the form of a key-value pair, field name: value; then there will be a blank line that also contains a carriage return and line feed, followed by the response entity, which is the data to be transmitted. In the above example it is a very simple HTML page. For the response status code, the first field key-value pair will be explained in more detail later. ## 5. HTTP request method The request method is the method used by the client to inform the server of its action intentions. Like giving an order. In the HTTP1.1 version, nearly 10 methods such as GET and POST are supported. It should be noted that method names are case-sensitive and require uppercase letters. Details below. **1.GET: Obtain resources** The GET method is used to request access to resources identified by URI. That is, it specifies the content of the response after the server processes the request. **2.POST: Transmitting the entity body** The POST method is used to transmit the entity body. Add a link after the url. **3.PUT: Transfer files** The PUT method is used to transfer files. Similar to the FTP protocol, the file content is included in the entity of the request message, and then the request is saved to the server location specified by the URL. **4.HEAD: Get the message header** The HEAD method is similar to the GET method, but the difference is that the HEAD method does not require return data. Used to confirm the validity of URI and resource update time, etc. **5.DELETE: Delete files** The DELETE method is used to delete files, which is the opposite method of PUT. DELETE is required to return the resource specified by the URL. **6.OPTIONS: Ask for supported methods** Because not all servers support the specified methods, some servers may prohibit some methods such as DELETE, PUT, etc. for security reasons. Then OPTIONS is used to ask the server for supported methods. **7.TRACE: Tracking Path** The TRACE method is a method that allows the web server to loop back the previous request communication to the client. This method is not commonly used. **8.CONNECT: Requires the use of tunnel protocol to connect to the proxy** The CONNECT method requires the establishment of a tunnel when communicating with the proxy server to implement TCP communication using the tunnel protocol. The SSL/TLS protocol is mainly used to encrypt communication content and then transmit it. Summary:

6. HTTP response status code

The status code is used to inform the client of the result of the server processing the request. With the status code, users can know whether the server successfully processed the request, failed, or was forwarded; this way, errors can be easily located. The status code consists of a 3-digit number plus a reason phrase. The first 3-digit number specifies the status category. There are 5 types in total.

There are more than 60 kinds of HTTP status codes, but you don’t need to remember them all, because most of them are not used frequently in work. There are about 16 commonly used types, which are introduced in detail below. (In fact, there are only 8 most commonly used ones, the ones with background colors below are)
1. 200: OK
There is nothing to say about this. It means that the request was successfully processed normally.
2. 204:No Content
The request was processed successfully, but no data entity was returned, and no entity was allowed to be returned. For example, a HEAD request may return 204 No Content, because HEAD only obtains header information. Here is a brief mention of 205 Reset Content. The difference between 205 Reset Content and 204 No Content is that not only no data entity is returned, but the form also needs to be reset to facilitate user input again.
3. 206: Partial Content
This is because the client uses Content-Range to specify the range of required entity data, and then after the server successfully processes the request, it returns the part of the data that the user needs instead of all of it. The request executed is GET. The return code is 206: Partial Content.
4. 301: Moved Permanently
Represents permanent orientation. This status code indicates that the requested resource has been assigned a new URL and that the resource’s currently specified URL should be used in the future. That is to say, if the URL corresponding to the resource has been saved as a bookmark, it should be re-saved according to the URL prompted by the Location header field.
5. 302:Found
Represents temporary redirection. This status code indicates that the requested resource has been assigned a new URL, but the difference from 301 is that 302 does not represent a permanent move, but is only temporary. That is to say, this URL may also change. It will not be updated if it is saved as a bookmark.
6. 303: See Other
The difference from 302 is that 303 clearly stipulates that the client should use the GET method.
7. 304:Not Modified
This status code indicates that when the client sends a conditional request, the server allows the request to access the resource, but the conditions are not met. The 304 status code returned does not contain any data entities. Although 304 is classified into 3XX, it has nothing to do with redirection.
8. 307: Temporary Redirect
Temporary redirection is the same as 302 Found, but 302 will change POST to GET, while 307 will not.
9. 400: Bad Request
400 indicates that there is a syntax error in the request message. Need to be modified before sending again.
10. 401: Unauthorized
This status code indicates that the request sent requires authentication information that passes HTTP authentication.
11. 403:Forbidden
Indicates that the requested resource has been denied. Not gaining access to the server, IP banned, etc.
12. 404:Not Found
Indicates that the requested resource cannot be found on the server. Of course, it can also be used when the server rejects the request and does not want to explain the reason.
13. 408: Request Timeout
Indicates that the client request has timed out, which means that the server does not receive the client’s request within a certain period of time after the client and server establish a connection.
14. 500: Internal Server Error
Indicates that an error occurred on the server side when executing the request. It is most likely a bug or temporary failure of the server program.
15. 503: Service Unavailable
?Indicates that the server is temporarily overloaded or is undergoing downtime for maintenance and is currently unable to process requests. If you know the time required to resolve the above situation in advance, it is best to write the Retry-After field and return it to the client.
16. 504: Getaway Timeout
Gateway timeout is the timeout when the proxy server waits for the application server to respond. The difference from 408 Request Timeout is that 504 is caused by the server rather than the client.

7. Introduction to related APIs

(1) Domain name resolution

/*
  * Resolve the name of the service location (e.g. hostname) and/or
  *Service name and returns a set of socket addresses and related
  *Information used to create the socket used for addressing
 * @param nodename The descriptive name or address string of the host
 * (for NULL -> local address local address)
 * @param servname The port number is a NULL string
 * @param hints structure contains input values for setting socktype and protocol
 * @param res Pointer to a pointer to store the result (set to NULL on failure)
 * @return Returns 0 on success, non-zero on failure
 * */
Int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)

(2) Create socket, Baidu socket function

 int socket(int family, int type, int protocol);
family specifies the protocol family; the type parameter specifies the socket type: SOCK_STREAM, SOCK_DGRAM, SOCK_RAW; protocol is usually assigned the value "0". The socket() call returns an integer socket descriptor, which you can use in subsequent calls.

(3), connection service connect

 int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
sockfd is the sock descriptor of the destination server; serv_addr is the IP address and port number of the server; addrlen is usually sizeof(struct sockaddr_in);

8. Software design

The software is modified based on the original code of idf_wifi_sta.c
After connecting to wifi, start executing the http task:

①.Resolve DNS domain name
First fill addrinfo

const struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};

Define the Socket address pointer to obtain the Socket address from the function

getaddrinfo(WEB_SERVER, WEB_PORT, & amp;hints, & amp;res);

struct addrinfo {<!-- -->
    int ai_flags; /* Input flags. */
    int ai_family; /* Address family of socket. */
    int ai_socktype; /* Socket type. */
    int ai_protocol; /* Protocol of socket. */
    socklen_t ai_addrlen; /* Length of socket address. */
    struct sockaddr *ai_addr; /* Socket address of socket. */
    char *ai_canonname; /* Canonical name of service location. */
    struct addrinfo *ai_next; /* Pointer to next in list. */
};

After resolving the IP address from the domain name
②Create and connect Socket

s = socket(res->ai_family, res->ai_socktype, 0);
connect(s, res->ai_addr, res->ai_addrlen)

③, read and write http package

write(s, REQUEST, strlen(REQUEST)
read(s, recv_buf, sizeof(recv_buf)-1)

9. Example

Copy the idf_wifi sta project and change its name to idf_wifi_http (because this routine is based on idf_wifi sta). Change the file name to idf_wifi_http.c and change the makefile file to PROJECT_NAME := idf_wifi_http. Then copy the code to test.

/********************************************** ************************
* File name: idf_wifi_http.c
*               founder:            
* Creation date:
* Modified by:
* Modification date:
* Version number: V1.1
*               Remark:
*               company:
*************************************************** ******************/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "nvs.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
static const char *TAG = "WIFI_HTTP";
#define WEB_SERVER "www.elecfans.com"
#define WEB_PORT "80"
#define WEB_URL "/tags/"
//http request package
static const char *REQUEST = "GET "WEB_URL" HTTP/1.1\r\
"
    "Host: "WEB_SERVER"\r\
"
    "Connection: close\r\
"
    "\r\
";

//event flag group
static EventGroupHandle_t xCreatedEventGroup_WifiConnect = NULL;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static int retry_num = 0;
#define HttpGet_TASK_STACK_SIZE 8192
#define HttpGet_TASK_PRIO 2
//task handle
static TaskHandle_t xHandleTaskHttpGet = NULL;
static void vTaskHttpGet(void *pvParameters);
/****************************************************** **********************
* Function:
* Description: wifi callback function
* Parameters:
* Return: None
* Remark:
*************************************************** **********************/
static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{<!-- -->
    ESP_LOGI(TAG, "event_base: %s ; event_id : %d",event_base,event_id);
    if (event_base == WIFI_EVENT & amp; & amp; event_id == WIFI_EVENT_STA_START)
    {<!-- -->
        esp_wifi_connect();//Start connecting
    }
    else if (event_base == WIFI_EVENT & amp; & amp; event_id == WIFI_EVENT_STA_DISCONNECTED) //When wifi is disconnected
    {<!-- -->
        if (retry_num < CONFIG_ESP_MAXIMUM_RETRY) //Number of reconnections
        {<!-- -->
            esp_wifi_connect();
            retry_num + + ;
            ESP_LOGI(TAG, "retry to connect to the AP");
        }
        else
        {<!-- -->
            xEventGroupSetBits(xCreatedEventGroup_WifiConnect, WIFI_FAIL_BIT);
            xEventGroupClearBits(xCreatedEventGroup_WifiConnect, WIFI_CONNECTED_BIT);
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    }
    else if (event_base == IP_EVENT & amp; & amp; event_id == IP_EVENT_STA_GOT_IP)//Get IP
    {<!-- -->
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR( & amp;event->ip_info.ip));
        retry_num = 0;
        xEventGroupSetBits(xCreatedEventGroup_WifiConnect, WIFI_CONNECTED_BIT);
        xEventGroupClearBits(xCreatedEventGroup_WifiConnect, WIFI_FAIL_BIT);
    }
}
/****************************************************** **********************
* Function:
* Description: The wifi st initialization code is relatively fixed and generally does not need to be modified.
* Parameters:
* Return: None
* Remark:
*************************************************** **********************/
void wifi_init_sta(void)
{<!-- -->
    ESP_ERROR_CHECK(esp_netif_init()); //Initialize TCP/IP stack and esp-netif
    ESP_ERROR_CHECK(esp_event_loop_create_default()); //Create the default event loop
    esp_netif_create_default_wifi_sta();//Create the default WIFI STA.

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();//Initialize the system default data for the wifi_init_config_t structure
    ESP_ERROR_CHECK(esp_wifi_init( & amp;cfg));//Initialize wifi using default parameters

    //Register callback function during wifi connection process
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, & amp;event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, & amp;event_handler, NULL));
    ESP_LOGI(TAG, "WIFI_EVENT :%s",WIFI_EVENT);
    ESP_LOGI(TAG, "IP_EVENT :%s",IP_EVENT);
    //Set the account and password in menuconfig
    wifi_config_t wifi_config = {<!-- -->
        .sta = {<!-- -->
            .ssid = CONFIG_ESP_WIFI_SSID,
            .password = CONFIG_ESP_WIFI_PASSWORD
            //.ssid = "ssid",
            //.password = "password"
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );//Set to sta mode
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, & amp;wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start() );//Start
    ESP_LOGI(TAG, "wifi_init_sta finished.");
}
/****************************************************** **********************
* Function:
* Description: Main function
* Parameters:
* Return: None
* Remark:
*************************************************** ************************/
void app_main()
{<!-- -->
    //Initialize NVS
   esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {<!-- -->
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    //Create an event flag group to wait for wifi connection
    xCreatedEventGroup_WifiConnect = xEventGroupCreate();
    //WIFI st initialization
    wifi_init_sta();

    xTaskCreate(vTaskHttpGet, //Task function
                "vTaskHttpGet", // task name
                HttpGet_TASK_STACK_SIZE, // Task stack size, unit word, which is 4 bytes
                NULL, //Task parameters
                HttpGet_TASK_PRIO, //Task priority
                 &xHandleTaskHttpGet);
}

static void vTaskHttpGet(void *pvParameters)
{<!-- -->
    //Waiting for a successful connection, or if the connection is already disconnected, this function will always block until there is a connection.
   xEventGroupWaitBits(xCreatedEventGroup_WifiConnect,//Event flag group handle
        WIFI_CONNECTED_BIT, // Wait for bit0 and bit1 to be set
        pdFALSE, //bit0 and bit1 are cleared when TRUE exits, bit0 and bit1 are not cleared when pdFALSE exits
        pdTRUE, //Set to pdTRUE to wait for both bit1 and bit0 to be set, pdFALSE to wait for either bit1 or bit0 to be set
        portMAX_DELAY); //Wait for the delay time and keep waiting
    const struct addrinfo hints = {<!-- -->
        .ai_family = AF_INET,
        .ai_socktype = SOCK_STREAM,
    };
    struct addrinfo *res;
    struct in_addr *addr;
    int s, r;
    char recv_buf[64];

    for (;;)
    {<!-- -->
        //DNS domain name resolution
        int err = getaddrinfo(WEB_SERVER, WEB_PORT, & amp;hints, & amp;res);
        if(err != 0 || res == NULL)
        {<!-- -->
            ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p\r\
", err, res);
            vTaskDelay(1000/portTICK_PERIOD_MS);
            continue;
        }
        //Print the obtained IP
        addr = & amp;((struct sockaddr_in *)res->ai_addr)->sin_addr;
        ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));

        //Create socket
        s = socket(res->ai_family, res->ai_socktype, 0);
        if(s < 0)
        {<!-- -->
            ESP_LOGE(TAG, "... Failed to allocate socket.\r\
");
            close(s);
            freeaddrinfo(res);
            vTaskDelay(1000/portTICK_PERIOD_MS);
            continue;
        }
        //connect ip
        if(connect(s, res->ai_addr, res->ai_addrlen) != 0)
        {<!-- -->
            ESP_LOGE(TAG, "... socket connect failed errno=%d\r\
", errno);
            close(s);
            freeaddrinfo(res);
            vTaskDelay(4000/portTICK_PERIOD_MS);
            continue;
        }
        freeaddrinfo(res);
        //Send http packet
        if (write(s, REQUEST, strlen(REQUEST)) < 0)
        {<!-- -->
            ESP_LOGE(TAG, "... socket send failed\r\
");
            close(s);
            vTaskDelay(4000/portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... socket send success");

        //clear cache
        memset(recv_buf,0,sizeof(recv_buf));
        /* Read HTTP response */
        do {<!-- -->
            bzero(recv_buf, sizeof(recv_buf));
            r = read(s, recv_buf, sizeof(recv_buf)-1);
            for(int i = 0; i < r; i + + ) {<!-- -->
                putchar(recv_buf[i]);
            }
        } while(r > 0);
        close(s);

        for(int countdown = 20; countdown >= 0; countdown--)
        {<!-- -->
            ESP_LOGI(TAG, "%d... ", countdown);
            vTaskDelay(1000/portTICK_PERIOD_MS);
        }
        ESP_LOGI(TAG, "Starting again!");
    }
}

10. Debugging results

Most of the browsers are https related websites, so I found a link http://www.elecfans.com/tags/

Chinese characters cannot be displayed, so garbled characters appear.
Press F12 on the browser to open the debugging window to compare the received data

All article source codes: https://download.csdn.net/download/lu330274924/88518092