ESP8266_15天气预报之TCP的GET操作

前面几节,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,即可获取。

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据