Espressif HTTP AT 命令入门 (一)
最近使用乐鑫公司推出的ESP32芯片去做项目,其实要做的工作很简单,只需要下载对应ESP32芯片的AT固件即可 ( 写本篇文章的时候最新的版本为 v2.1.0.0 ),其余逻辑层面的工作只需要通过AT指令操作即可。乐鑫的AT指令集很全,基本可以满足项目的开发需求,使用到的核心AT指令为HTTP指令。HTTP指令为 AT 固件默认支持指令,直接使用即可。
本篇文章的目的:
- HTTP 协议入门
HTTP 协议
概念
HTTP(超文本传输协议HyperText Transfer Protocol) 协议是互联网的基础协议,属于 TCP/IP 四层模型中的应用层协议。由此可见,HTTP 协议是基于 TCP/IP 协议之上的应用层协议。
版本
HTTP协议经历了四个版本的变迁,对各个版本的不同各位看官可以自行百度,这里只列出对应各个版本的关键信息。
- HTTP/0.9 ( 默认使用 80 端口,仅仅支持 GET 命令 )
- HTTP/1.0 ( 引入 POST 命令和 HEAD 命令 )
- HTTP/1.1 ( 目前最流行版本 )
- HTTP/2 ( 复用 TCP 连接 )
工作原理
HTTP 协议基于客户端/服务器模式。典型的工作流程如下:
1). 客户端与服务器建立 TCP 连接
2). 客户端向服务器提出请求
3). 服务器根据客户端提出的请求返回对应的应答
4). 客户端与服务器断开 TCP 连接
特别需要注意的客户端与服务器建立的 HTTP 连接是一次性的,即当服务器返回给客户端请求结果后,这次的 HTTP 连接就关闭了。客户端下次请求必须再次和服务器重新建立 HTTP 连接。
这里用到的名词为 HTTP 连接,并不是 TCP 连接,这是两个概念,需要区分。HTTP 连接是建立在 TCP 连接之上的。
特性
从 HTTP 的工作原理角度看,HTTP 协议的特性很多,但是最主要的两个特性是无连接和无状态。
-
无连接:每次 HTTP 连接仅仅处理一个请求。服务器返回客户端的请求后,这次的 HTTP 连接也就意味着断开了。该特性可以大大提高服务器的执行效率。
-
无状态:HTTP 协议对于请求/应答过程不保存状态信息。意味着后续的处理如果需要前面的信息,就只能通过重传来实现。该特性可以减轻服务器的记忆负担,提高服务器的响应速度。
报文格式
HTTP 协议既然是一种应用层协议,自然有属于自己协议的报文格式。
HTTP 协议的报文主要分为两种:
- 请求报文
- 响应报文
请求报文
在网上找了好一会 HTTP 请求报文的示意图,没有找到自己满意的,又不想自己动手画,只能找一个还算是可以的示意图。
HTTP 请求报文主要可以分为三个部分:
- 请求行
- 请求头部
- 请求数据
请求行
请求行由方法字段、URL 字段、版本字段组成。
-
方法
对于方法,我们一般用的比较多的是GET
和POST
。其余方法用到的时候在来百度补充。GET
:请求获取 URL 指定位置的资源 ( 类似 git pull )POST
:在 URL 所标识的资源后附加数据。这些数据会发送给服务器,由服务器进行处理 ( 类似 git push )
-
URL
原文请参考:http://blog.csdn.net/ergouge/article/details/8185219URL,全称为 UniformResourceLocator,中文叫统一资源定位符。作用是用来标识网络中某一处资源的地址。
以下面这个 URL 为例,说明下 URL 的组成。
http://www.aspxfans.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name
一个完整的 URL 由以下 7 个部分组成:
- 协议部分:该 URL 所表明的协议为
http
。除了http
之外,网络中还可以采用ftp
等多种协议。 - 域名部分:该 URL 的域名部分是
www.aspxfans.com
。也可以直接以该域名对应的 IP 地址取代。 - 端口部分:该 URL 的端口部分是
8080
。该部分并不是必须的,如果省略,将采用默认端口,一般来说默认端口为80
。 - 虚拟目录部分:该 URL 的虚拟目录部分为
/news/
。从端口部分后的第一个/
开始到最后一个/
为止,均属于虚拟目录部分。 - 文件名部分:该 URL 的文件名部分为
index.asp
。从虚拟目录部分的最后一个/
之后开始到符号?
之前,是文件名部分。如果没有符号?
,则到符号#
之前是文件名部分。如果符号?
和#
均没有,则文件名部分为虚拟目录部分的最后一个/
后开始到该 URL 结束。 - 参数部分:该 URL 的参数部分为
boardID=5&ID=24618&page=1
。从符号?
之后到符号#
之前,这中间的部分属于参数部分。 参数允许有多个,用分隔符&
进行分隔。 - 锚部分:该 URL 的锚部分为
name
。从符号#
开始到 URL 的结束的中间部分属于锚部分。
- 协议部分:该 URL 所表明的协议为
-
版本字段
该字段所代表的含义为客户端所采用的 HTTP 协议的版本。
请求头部
请求头部说白了就是由键值对组成。作用是允许客户端向服务器发送一些附加信息或者描述客户端自身的信息。
这个不多解释了,自己看图吧。
请求数据
请求数据的格式取决于请求头部中的 Content-Type 字段。
- 方法为
GET
时,请求数据基本为空 - 方法为
POST
时,需要填充上传给服务器的数据
请求报文抓包示例
概念介绍的差不多了,下面该进入实战环节了。
GET 请求包
这里我用 Wireshark 抓个 GET 请求包进行介绍 ( 如果不知道 Wireshark 的,及时叉掉浏览器,远离代码保平安 )
这里以乐鑫的 IOT 官网为例,入口为:http://iot.espressif.cn/
如图, Wireshark 还是不错的一款软件,都将抓到的包进行了识别。在加上我们对抓到的包进行一丢丢的过滤,GET 请求包就一目了然了。
继续利用 Wireshark 对 GET 请求包进行分析,对照上面的概念进行对号入座,是不是结果就呼之欲出了呢。
字段 | 值 |
---|---|
方法 | GET |
URL | /static/css/bootstrap.min.css |
版本 | HTTP/1.1 |
Host | iot.espressif.cn |
Connection | keep-alive |
User-Agent | User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 |
Accept | text/css,/;q=0.1 |
Referer | http://iot.espressif.cn/ |
Accept-Encoding | gzip, deflate |
Accept-Language | en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7 |
If-None-Match | W/“543f8b3b-18679” |
If-Modified-Since | Thu, 16 Oct 2014 09:09:15 GMT |
POST 请求包
POST 请求包的抓包比较麻烦,因为没有好的服务器来给我们练练手。不过办法总比困难多,我们可以通过抓取路由器的 POST 包。
一般来说,路由器就是一个小型的 WEB 服务器。我们设置 WI-FI 的信息时就是通过 HTTP 协议进行交互。这里我以修改 WIFI SSID 为 alson_test
为例抓包。
继续利用 Wireshark 对 POST 请求包进行分析,对照上面的概念进行对号入座,是不是结果就呼之欲出了呢。
字段 | 值 |
---|---|
方法 | POST |
URL | /api/ntwk/WlanGuideBasic?type=notshowpassall |
版本 | HTTP/1.1 |
Host | 192.168.3.1 |
connection | keep-alive |
content_length | 1139 |
accept | application/json, text/javascript, /; q=0.01 |
X-Requested-With | XMLHttpRequest |
_ResponseFormat | JSON |
User-Agent | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 |
Content-Type | application/json;charset=UTF-8;enp |
Origin | http://192.168.3.1 |
Referer | http://192.168.3.1/html/advance.html |
Accept-Encoding | gzip, deflate |
Accept-Language | en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7 |
truncated]Cookie | test=cookietest; SessionID_R3=8kpx08uu4HGG0Uiu7Viy0Q2sGMt0i3lGJyYfDmikkXVs3ky20PERjTseUoeuWmErjCM0Wi0gXLD861gsXJiDajk8k0H1j0hEUh9azgWJ40wET6S16PtO9sJa90tQnO1A; encn=bdcd0e39395af486f3195f45429dcb0d16d47399bea473e0171b5 |
接着 \r\n
之后的实体就是请求数据了,示例中通过 content_type
指定了请求数据的组织格式是 application/json
,也就是 JSON 数据 ( 如果不懂 JSON ,还是趁早叉掉浏览器,远离代码保平安 ) 。
示例中的请求数据比较多,直接将请求数据以 HEX 格式转换成文本格式后,直接百度 JSON在线解析
,随便打开一个将刚才解析好的文本格式进行 JSON 数据自动格式化
即可。一眼就可以看到 config2g
中 ssid
的值为 alson_ap
。
响应报文
在网上找了好一会HTTP请求报文的示意图,没有找到自己满意的,又不想自己动手画,只能找一个还算是可以的示意图。
响应报文的报文格式其实和请求报文的报文格式差不多,也是由三部分组成:
- 状态行
- 首部行
- 实体
状态行
-
状态码
状态码由三位数字组成。
我们常见的比较典型的状态码如下:
- 200: OK - 客户端请求成功 ( 最鸡东的状态码 )
- 3xx: 一般来说和重定向有关,客户端需要采取进一步的操作
- 400: Bad Request - 客户端请求有语法错误,服务器不能解析
- 401: Unauthorized - 请求未授权 ( 一般来说都是权限问题,可以尝试在请求报文的头部中加入 Authorization )
- 403: Forbidden - 服务器收到请求,但是拒绝提供服务
- 404: Not Found - 请求资源不存在 ( 是不是在网上经常见到,哈哈~ )
首部行
状态行的内容也是以键值对的形式。
这个也不过多的解释,自己看图吧。
实体
服务器返回给客户端请求的具体对象。可以根据状态行中的 Content-Length
和 Content-Type
计算数据的长度和数据的类型。
响应报文抓包示例
GET 响应包
与上文的 GET 请求包抓包示例相同,对客户端的 GET 请求响应。
利用 Wireshark 对 GET 响应包进行分析,对照上面的概念进行对号入座,结果也很明显。
字段 | 值 |
---|---|
版本 | HTTP/1.1 |
状态码 | 200 |
原因短语 | OK |
Server | nginx/1.10.2 |
Date | Thu, 18 Mar 2021 13:22:20 GMT |
Content-Type | application/json |
Content-Length | 49 |
Connection | keep-alive |
实体部分的数据的数据类型是 application/json
,数据长度是 49 。下面以 JSON
方式显示实体部分 ( 如果不懂 JSON ,还是趁早叉掉浏览器,远离代码保平安 )
POST 响应包
与上文的 POST 请求包抓包示例相同,对客户端的 POST 请求响应。
利用 Wireshark 对 POST 响应包进行分析,对照上面的概念进行对号入座,结果也很明显。
字段 | 值 |
---|---|
版本 | HTTP/1.1 |
状态码 | 200 |
原因短语 | OK |
Cache-Control | no-cache, no-store, max-age=0, must-revalidate |
Pragma | no-cache |
Content-Type | application/javascript |
X-Download-Options | noopen |
X-Frame-Options | SAMEORIGIN |
X-XSS-Protection | 1; mode=block |
Content-Security-Policy | default-src ‘self’ ‘unsafe-inline’ ‘unsafe-eval’ |
X-Content-Type-Options | nosniff |
Content-Length | 109 |
实体部分的数据的数据类型是 application/javascript
,数据长度是 109 。这里就不多作分析了。
以上就是一些 HTTP 的基本概念。虽然没有继续深入的去学习,不过这些在项目中已经够用了。下一篇会对 ESP HTTP AT 指令进行讲解,敬请期待~