前面几节,TCP的基本操作聊了一些。接下来这几节,聊一聊HTTP协议下的GET操作。首先明确几个基本概念:
HTTP(HyperText Transfer Protocol,超文本传输协议)是一套计算机通过网络进行通信的规则,使HTTP客户端能够从HTTP服务器端请求到信息和服务,目前的版本号是1.1。
HTTP通讯机制是在一次完整的HTTP通讯过程中,客户端和服务器之间建立连接分为以下几个步骤。
1、建立连接: 其中包括:域名解析,TCP三次握手。
2、发送数据
3、返回数据
4、关闭连接
咱们这一节主要研究的是其中的前二个步骤:建立连接和发送数据。即域名如何解析,数据该以什么样的格式发送。
如何演示?天气预报?
是的,天气预报。这个东西虽然有点俗,但用来讲解,效果还是挺好的。
首先,去心知天气(自行百度,非广告)注册一个账户,然后购买一个免费版的产品。这时,你就能通过API查看全国任意城市的天气了。
使用方式,将 API 密钥中的“私钥”作为 API 请求中的 key 参数值:
https://api.seniverse.com/v3/weather/now.json?key=your_private_key&location=beijing&language=zh-Hans&unit=c
把连接中的加黑字体换成你的私钥,然后粘贴到浏览器,效果如下:
看不清图片的,看下面文字:
{“results”:[{“location”:{“id”:”WX4FBXXFKE4F”,”name”:”北京”,”country”:”CN”,”path”:”北京,北京,中国”,”timezone”:”Asia/Shanghai”,”timezone_offset”:”+08:00″},”now”:{“text”:”多云”,”code”:”4″,”temperature”:”27″},”last_update”:”2019-09-17T14:25:00+08:00″}]}
想看其它城市的天气,更换连接中的文字:beijing为你想要的城市即可。
先说域名解析,为什么要解析?
研究这个之前,先思考一个问题,我们上网的时候,究竟是怎么上的。以百度为例,我们输入的网址是:www.baidu.com或者http://www.baidu.com,再或者https://www.baidu.com。
严格来说,URL应该符合以下形式:
<协议>://<主机>:<端口>/<路径>?<参数>&<参数>
协议常用的有http、https或者ftp;“://”不能省略;主机就是“www”开头的网址,端口没有写的话,默认80;斜杠后面跟的是路径等等。对照这个格式,百度的网址可以写成这样:
http://www.baidu.com:80/index.html
所以,做域名解析的时候,要考虑这几方面的因素:协议、主机、端口、路径,也就是说你要把这几样因素都找到。域名解析的函数网上有很多公开的代码,我这里贴一个,仅供参考:
void ICACHE_FLASH_ATTR http_parse_request_url(char *URL,char *host,char *filename,unsigned short *port)
{
char *PA;
char *PB;
memset(host,0,sizeof(host));
memset(filename,0,sizeof(filename));
*port=0;
if(!(*URL)) return;
PA=URL;
if(!strncmp(PA,"http://",strlen("http://")))
PA=URL+strlen("http://");
if(!strncmp(PA,"https://",strlen("https://")))
PA=URL+strlen("https://");
PB=strchr(PA,'/');
if(PB){
memcpy(host,PA,strlen(PA)-strlen(PB));
if(PB+1){
memcpy(filename,PB+1,strlen(PB-1));
filename[strlen(PB)-1]=0;
}
host[strlen(PA)-strlen(PB)]=0;
}else{
memcpy(host,PA,strlen(PA));
host[strlen(PA)]=0;
}
PA=strchr(host,':');
if(PA)
*port=atoi(PA+1);
else
*port=80;
}
所以,解析完成之后,得到主机和路径,按照相应格式,组成数据包,发送给服务器,服务器就能返回相应的数据。
那么,ESP8266怎么发送?直接通过espconn_sent函数把数据发出去?那是肯定不行滴。需要一个特定的格式。HTTP请求数据格式如下:
当浏览器发送请求时,它要向服务器发送一个数据块,也就是请求信息,其中信息由三部分组成。
1. 请求方法 URI协议/版本
2. 请求头(Request Header)
3. 请求正文
示范代码如下:
GET/sample.jspHTTP/1.1
Accept:image/gif.image/jpeg,*/*
Accept-Language:zh-cn
Connection:Keep-Alive
Host:localhost
User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0)
Accept-Encoding:gzip,deflate
再比如,当我使用浏览器访问网址的时候,通过抓包工具,可以看到如下信息:
这些内容,有些是可以不要的。所以最终整理一下,以访问心知天气的API为例,实际的内容格式如下:
GET v3/weather/now.json?key=your_private_key&location=beijing&language=zh-Hans&unit=c HTTP/1.1
Accept: */*
Host: api.seniverse.com
Connection: Keep-Alive
GET后面跟的是前面那个API网址中,api.seniverse.com后面的那一串字符,然后是“HTTP/1.1”。由于格式原因,没有显示在同一行,实际应用的时候放在同一行即可。
实际应用中,每次输入不同的API链接,我们不可能手动把前面的host和后面的字符串拆分开,所以需要上面的解析函数,用来判断哪部分是host,哪部分是字符串。
程序修改完成,保存、清理、编译、下载一条龙,然后重新上电。这里借助串口助手来查看效果。效果如下所示:
从receive data开始,都是收到的信息。我这里查看了廊坊的天气,显示晴天,28度,还可以~
但是目前这个数据只能通过串口打印出来,而且还有一定的格式,需要对格式进行解析,这部分下一节再说。
完整工程源码,请关注公众号:单片机爱好者,回复关键字:ESP8266,即可获取。