文章目录
参考资料:《计算机网络(第7版)-谢希仁》
1 HTTP Client 实验工程简介
本实验是在app-wifi-station例程基础之上添加乐鑫官方例程esp_http_client所做的实验,当然也可以直接使用官方例程进行实验,这里使用app-wifi-station工程进行实验是因为为了学习的连贯性,因为在app-wifi-station工程中实现了连接wifi热点;另一方面也是为了学习工程的移植。
- app-wifi-station例程:作用是连接指定wifi;
- 乐鑫官方例程esp_http_client:作用是参考http作为client的各种功能。
1.1 实验工程选择
1.1.1 新建自己的工程app-http-client
- 复制app-wifi-station例程并改名为app-http-client;
- 将编译生成的可烧录文件更名为app-http-client;
- 删除例程内旧的sdkconfig配置相关文件(包括main文件夹下),将官方例程esp_http_client内sdkconfig配置相关文件复制过来,完成后如下:
- 将examples\common_components\protocol_examples_common文件夹下的Kconfig.projbuild文件覆盖app-http-client\main文件夹下的Kconfig.projbuild,如下:
- 将官方例程下的howsmyssl_com_root_cert.pem文件复制到main文件夹下,并在main文件夹下的CMakeLists.txt、component.mk文件内增加该文件
- 将官方例程esp_http_client_example.c文件复制过来,更名为user_http_client.c,并添加进CMakeLists.txt
- 新建user_http_client.h文件
- 打开user_http_client.c文件,将app_main改为user_http_client_init,并删除多于的函数,完成后如下:
- 将user_http_client_init函数在user_http_client.h文件中作声明,再添加到station_example_main.c文件下的app_main函数中
- 使用idf.py menuconfig指令配置wifi账号和密码
- 使用idf.py build指令编译工程
1.1.2 直接使用官方例程esp_http_client
- 直接将官方例程复制到自己做实验的文件夹下;
- 使用idf.py menuconfig指令配置wifi;
- 使用idf.py build编译即可;
注意:
- 确保 examples\common_components\protocol_examples_common 该路径下有如下官方库文件
- protocol_examples_common的作用就是连使用wifi或 Ethernet(以太网) 连接
1.2 统一资源定位符URL
1.2.1 URL的格式
统一资源定位符URL(Uniform Resource Locator) 是用来表示从互联网上得到的资源位置和访问这些资源的方法。URL实际上就是在互联网上资源的地址。显然, 互联网上的所有资源, 都有一个唯一确定的URL。这里所说的 “ 资源” 是指在互联网上可以被访问的任何对象, 包括文件目录、 文件、 文档、 图像、 声音等, 以及与互联网相连的任何形式的数据。
URL相当于一个文件名在网络范围的扩展。 因此, URL 是与互联网相连的机器上的任何可访问对象的一个指针。 由于访问不同对象所使用的协议不同, 所以URL还指出读取某个对象时所使用的协议。 URL的一般形式由以下四个部分组成:
<协议>://<主机>:<端口>/<路径>
<协议>就是指使用什么协议来获取该万维网文档。 现在最常用的协议就是http(超文本传送协议HTTP),其次是ftp(文件传送协 议FTP)。
<主机>就是指出这个万维网文档是在哪一台主机上,即该主机在互联网上的域名。
<端口>就是指协议相对应的端口,如HTTP的默认端口号是80, 通常可省略。
<路径>就是指在该主机下资源存放的位置。
1.2.2 使用HTTP的URL
对于万维网的网点的访问要使用HTTP协议。 HTTP 的URL 的一般形式是:
http://<主机>:<端口>/<路径>
HTTP的默认端口号是80, 通常可省略。 若再省略文件的〈路径〉项, 则URL就指到互联网上的某个主页(home page)。
例如:https://www.espressif.com/
只显示主页内容如果添加<路径>则可以链接该主机下各种资源
例如:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/get-started/index.html
这里是乐鑫编程指南页面的URL。注意:上面的URL中使用了指向文件的路径, 而文件名就是最后的index.html。 后缀html (有时可写为htm)表示这是一个用超文本标记语言HTML写出的文件。
1.3 超文本传送协议 HTTP
HTTP协议定义了浏览器(即万维网客户进程)怎样向万维网服务器请求万维网文档,以及服务器怎样把文档传送给浏览器。
1.3.1 HTTP的报文结构
HTTP 有两类报文:
(1) 请求报文一一从客户向服务器发送请求报文, 见图6-12(a)。
(2) 响应报文一一从服务器到客户的回答, 见图6-12(b)。
由于HTTP是面向文本的(text-oriented), 因此在报文中的每一个字段都是 一些ASCII码串, 因而各个字段的长度都是不确定的。
HTTP 请求报文和响应报文都是由三个部分组成的。 可以看出, 这两种报文格式的区别就是开始行不同。
(1)开始行, 用于区分是请求报文还是响应报文。 在请求报文中的开始行叫做请求行(Request-Line), 而在响应报文中的开始行叫做状态行(Status-Line)。 在开始行的三个字段之间都以空格分隔开, 最后的 “CR” 和 “LF” 分别代表 回车 和 换行。
(2)首部行, 用来说明浏览器、 服务器或报文主体的一些信息。 首部可以有好几行, 但也可以不使用。在每一个首部行中都有首部字段名和它的值,每一行结束的地方都要有“回车”和“换行”,整个首部行结束时 ,还有一空行将首部行和后面的实体主体分开。
(3)实体主体(entity body), 在请求报文中一般都不用这个字段, 而在响应报文中也可能没有这个字段。
下面先介绍HTTP请求报文的一些主要特点。
请求报文的第一行 “请求行” 只有三个内容, 即方法, 请求资源的URL, 以及HTTP的版本。
请注意: 这里的名词 “ 方法 ” (method) 是面向对象技术中使用的专门名词。 所谓 “ 方法” 就是对所请求的对象进行的操作, 这些方法实际上也就是一些命令。 因此, 请求报文的类型是由它所采用的方法决定的。 这些常用的方法如下所示:
-
请求报文
下面是HTTP的请求报文的开始行〈即请求行)的格式。请注意,在GET后面有一个空格,接着是某个完整的URL,其后面又有个空格,最后是HTTP/1.1。
GET http://www.xyz.edu.cn/dir/index.htm HTTP/1.1
下面是一个完整的HTTP请求报文的例子:
在请求行使用了相对URL(即省略了主机的域名〉是因为下面的首部行(第2行〉给出了主机的域名。第3行是告诉服务器不使用持续连接,表示浏览器希望服务器在传送完所请求的对象后即关闭TCP连接。这个请求报文没有实体主体。 -
响应报文
再看一下HTTP响应报文的主要特点。
每一个请求报文发出后,都能收到一个响应报文。响应报文的第一行就是状态行。
状态行包括三项内容,即HTTP的版本,状态码,以及解释状态码的简单短语。
状态码(Status-Code)都是三位数字的,分为5大类,这5大类的状态码都是以不同的数字开头的。
1xx表示通知信息,如请求收到了或正在进行处理。
2xx表示成功,如接受或知道了。
3xx表示重定向,如要完成请求还必须采取进步的行动。
4xx表示客户的差错,如请求中有错误的语法或不能完成。
5xx表示服务器的差错,如服务器失效无法完成请求。
1.4 HTTP实验工具httpbin.org
httpbin这个网站能测试 HTTP 请求和响应的各种信息,比如 cookie、ip、headers 和登录验证等,且支持 GET、POST 等多种方法,对 web 开发和测试很有帮助。即你可以向他发送请求,然后他会按照指定的规则将你的请求返回(查看你所发送请求中的信息)。,网页如下图所示
官方网站:httpbin.org
开源地址:httpbin.org
常用接口列表:
1.5 实验分析
函数详细分析请参考:ESP HTTP Client
HTTP 配置参数
/**
* @brief HTTP configuration
*/
typedef struct {
const char *url; /*统一资源定位符!< HTTP URL, the information on the URL is most important, it overrides the other fields below, if any */
const char *host; /*服务器域名或ip地址 !< Domain or IP as string */
int port; /*端口 http默认80 https 默认443!< Port to connect, default depend on esp_http_client_transport_t (80 or 443) */
const char *username; /*用户名,认证时使用!< Using for Http authentication */
const char *password; /*用户密码,认证时使用!< Using for Http authentication */
esp_http_client_auth_type_t auth_type; /*认证方式!< Http authentication type, see `esp_http_client_auth_type_t` */
const char *path; /*路径!< HTTP Path, if not set, default is `/` */
const char *query; /*请求参数!< HTTP query */
const char *cert_pem; /*证书!< SSL server certification, PEM format as string, if the client requires to verify server */
const char *client_cert_pem; /*!< SSL client certification, PEM format as string, if the server requires to verify client */
const char *client_key_pem; /*!< SSL client key, PEM format as string, if the server requires to verify client */
esp_http_client_method_t method; /*!< HTTP Method */
int timeout_ms; /*请求超时!< Network timeout in milliseconds */
bool disable_auto_redirect; /*!< Disable HTTP automatic redirects */
int max_redirection_count; /*!< Max redirection number, using default value if zero*/
http_event_handle_cb event_handler; /*!< HTTP Event Handle */
esp_http_client_transport_t transport_type; /*!< HTTP transport type, see `esp_http_client_transport_t` */
int buffer_size; /*!< HTTP receive buffer size */
int buffer_size_tx; /*!< HTTP transmit buffer size */
void *user_data; /*!< HTTP user_data context */
bool is_async; /*!< Set asynchronous mode, only supported with HTTPS for now */
bool use_global_ca_store; /*!< Use a global ca_store for all the connections in which this bool is set. */
bool skip_cert_common_name_check; /*!< Skip any validation of server certificate CN field */
} esp_http_client_config_t;
1.5.1 HTTP 实验之使用URL获取资源
- 方法(method)GET
static void http_rest_with_url(void)
{
char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
/**
* NOTE: All the configuration parameters for http_client must be spefied either in URL or as host and path parameters.
* If host and path parameters are not set, query parameter will be ignored. In such cases, query parameter should be specified in URL.
*
* If URL as well as host and path parameters are specified, values of host and path will be considered.
*/
/*有些参数没有配置则会使用默认参数*/
esp_http_client_config_t config = {
.url = "http://httpbin.org/get",
.method = HTTP_METHOD_GET,
.event_handler = _http_event_handler,
.user_data = local_response_buffer, // Pass address of local buffer to get response
};
esp_http_client_handle_t client = esp_http_client_init(&config);
// GET
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
}
// ESP_LOG_BUFFER_HEX(TAG, local_response_buffer, strlen(local_response_buffer)); /*以十六进制形式输凿/
ESP_LOGI(TAG, "recv data ---2 = %d %s\r\n", strlen(local_response_buffer), local_response_buffer); //打印数据
esp_http_client_cleanup(client);
}
编译程序,烧录到ESP32开发板,并通过串口打印,数据如下:
- 方法(method)POST
static void http_rest_with_url(void)
{
char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
/**
* NOTE: All the configuration parameters for http_client must be spefied either in URL or as host and path parameters.
* If host and path parameters are not set, query parameter will be ignored. In such cases, query parameter should be specified in URL.
*
* If URL as well as host and path parameters are specified, values of host and path will be considered.
*/
/*有些参数没有配置则会使用默认参数*/
esp_http_client_config_t config = {
.url = "http://httpbin.org/get",
.method = HTTP_METHOD_GET,
.event_handler = _http_event_handler,
.user_data = local_response_buffer, // Pass address of local buffer to get response
};
esp_http_client_handle_t client = esp_http_client_init(&config);
//POST
//下面有些参数会被重新覆盖,如url、method
const char *post_data = "{\"field1\":\"value1\"}";
esp_http_client_set_url(client, "http://httpbin.org/post");
esp_http_client_set_method(client, HTTP_METHOD_POST);
esp_http_client_set_header(client, "Content-Type", "application/json");
esp_http_client_set_post_field(client, post_data, strlen(post_data));
err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
}
ESP_LOGI(TAG, "POST recv len = %d ,data:\r\n %s ", strlen(local_response_buffer), local_response_buffer); //打印数据
esp_http_client_cleanup(client);
编译程序,烧录到ESP32开发板,并通过串口打印,数据如下:
1.5.2 HTTP 实验之使用host和path获取资源
使用“host和path”和使用“URL”获取的资源是一样的
- 方法(method)GET
static void http_rest_with_hostname_path(void)
{
char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
esp_http_client_config_t config = {
.host = "httpbin.org",
.path = "/get",
.query = "ESP", //在url中添加请求参数
.transport_type = HTTP_TRANSPORT_OVER_TCP,
.event_handler = _http_event_handler,
.user_data = local_response_buffer, // Pass address of local buffer to get response
};
esp_http_client_handle_t client = esp_http_client_init(&config);
// GET
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
}
ESP_LOGI(TAG, "GET recv len = %d ,data:\r\n %s ", strlen(local_response_buffer), local_response_buffer); //打印数据
esp_http_client_cleanup(client);
}
编译程序,烧录到ESP32开发板,并通过串口打印,数据如下: