您的位置:首页 > 其它

基于STM32控制ESP8266向API接口发送GET请求并解析返回数据

2020-02-07 08:28 1431 查看

快速索引

  • 使用ESP8266连接服务器并发送GET请求
  • 解析返回结果
  • 前文写道在使用STM32控制ESP8266通过TCP方式连接上服务器,然后可以和服务器进行通信,收发数据。本文将以苏宁免费的时间接口为例:(👈可以直接点击查看返回结果)
    http://quan.suning.com/getSysTime.do
    演示如何向服务器的API接口发送GET请求报文,并且解析数据。(博主对网络很不了解,如有错误的地方还请指正)

    GET请求格式

    具体GET请求的过程我不做多余解释,以免有错误误导读者,如想了解可以搜索一下请求头内容以及解释。
    我们在连接服务器成功后可以向服务器发送以下内容,就可以获得相应的结果。

    GET http://quan.suning.com/getSysTime.do HTTP/1.1
    Host: quan.suning.com
    
    //结尾需要有一个空行并且回车换行,也就是说要有两个换行回车

    实际上GET请求全部内容有九行,这里只要发送请求的资源名称以及使用的协议版请求的服务器地址 就可以了。

    使用TCP助手测试

    在使用ESP8266连接之前,我们先用TCP助手连接服务器,并发送请求测试一下,以保证这个方案确实可行(TCP助手发送的数据和我们使用ESP8266发送的数据一模一样。所以用它来测试向服务器发送GET请求的数据,可以不用改动内容直接使用)。

    查看API接口的服务器地址和端口号

    因为TCP助手的局限,我们连接时必须先知道API接口的服务器地址和端口号。但是正式使用ESP8266的时候就不必要了,直接使用域名就可以连接。
    简单的查看地址的方法有很多,在这里博主介绍使用浏览器方法(测试IE浏览器好像不行,我是用的是QQ浏览器)。
    1.直接在浏览器地址栏输入苏宁时间接口的URL,就会看到返回的数据内容(是一串json数据)
    2.点击键盘F12,选择Network页签,然后刷新网页,即可看到Name下有两个文件

    3.点击第一个文件即可查看详情。里面包含了整个过程收发的内容。可以看到请求的URL,请求方式,和请求的地址(你看到的可能和我的不一样,都可以使用)

    使用TCP助手连接

    打开TCP调试助手然后输入地址和端口号,点击连接网络即可

    至此,我们的准备工作就完成了。此时就相当于我们的ESP8266连接服务器成功。

    使用TCP助手发送GET请求报文

    下面将我前文说到的报文黏贴进去(请注意格式),点击发送按钮很快就会收到服务器发送回来的数据。

    数据包含响应报文和消息体。
    第一行为状态行:200 OK 即是请求成功
    空行后面紧接着的就是消息体,内容应该与浏览器显示的结果一致。

    如果返回结果有问题,多数是因为复制的问题。删除干净后,输入请求报文内容至发送区。
    至此,我们使用TCP调试助手测试成功。

    使用ESP8266连接服务器并发送GET请求

    如果你已经实现ESP8266连接服务器,并且能收发数据,难么直接使用发送数据命令将请求报文发送出去就可以了。
    如果还没有实现,那么可以按照我的博文基于STM32单片机控制ESP8266连接服务器(包含C源码)中的方法来操作。

    下面展示具体实现代码:

    //头文件中宏定义内容
    //时间地址和服务器
    #define ESP_TIME_TCP_ADDRESS "quan.suning.com"
    #define ESP_TIME_TCP_POINT "80"
    //GET请求报文
    #define ESP_TIME_INFO  "GET http://quan.suning.com/getSysTime.do HTTP/1.1\r\nHost: quan.suning.com\r\n\r\n"
    
    //开启透传模式后,直接通过串口向ESP8266发送报文
    USART_Send_String(USART2, ESP_TIME_INFO); //发送GET请求报文,获得返回结果
    while(!(ESP_RX_STATE > 0));  //判断接收标志
    /*
    此处写收到结果后做的解析处理
    */
    ESP_RX_STATE --;//解析数据置位

    如此下来,我们发送了GET请求并且还能接受到返回的结果,是不是超简单。那么如何处理结果呢?

    解析返回结果

    我们收到的数据格式为json格式,这是一种广泛使用数据交换格式。有专用的cJSON库可以进行解析,具体这里就不解释怎么使用了,博主使用另外的笨方法:暴!力!破!解!

    解析数据

    因为我们的数据格式非常固定,我可以针对这个格式进行解析。再来回看下接收到的内容:
    {“sysTime2”:“2019-11-02 22:38:52”,“sysTime1”:“20191102223852”}
    使用了两种时间表示方法,都可以使用。从"sysTime1"后的第三位开始就是我们需要的结果,因此我只要使用函数 strstr()函数定位到"sysTime1"的位置往后移动11位(strstr函数返回的是查找的字符串的首地址)就可以了。

    data_pt = strstr((const char *) ESP_RX_BUF.buf,(const char *)"sysTime1");   //寻找到时间结果的地址,首地址返回给字符类型的指针变量(char*) data_pt

    年的首地址移动11位;

    year_string = data_pt + YERA_ADD_DRES;   //年份地址

    月份首地址移动15位;
    日期首地址移动17位;
    小时首地址移动19位;
    分钟首地址移动21位;
    秒钟首地址移动23位;
    以此类推可以得到每个数据的位置(其实直接可以当一个字符串处理)。

    处理数据

    我们其实是得到了字符串类型的时间数据,已经可以直接使用了。博主为了方便运算继续进行了数据转换,以便其他位置的使用。

    获得年:

    //获得年函数(因为以年开始的字符串长度过长,所以使用不同的方法)
    //输入值是年位置的地址
    //返回值是 整型的10进制四位数
    int Get_Year(char *y)
    {
    int year_return;
    char *year_temp;
    char year[5] = {0};
    char i;
    //年的获取需要提取一次字符串,否则无法读取
    year_temp = y;
    for(i = 0; i<4; i++)
    {
    year[i] = *year_temp;
    year_temp ++;
    }
    
    year_return =  atoi(&year[0]);
    return year_return;
    }

    获得月份:

    //获得月份函数
    //输入值是月份位置的地址
    //返回值是 整型的10进制两位数
    int Get_Moonth(char *m)
    {
    int moonth_return;
    moonth_return = atoi(m)/100000000;   //取月份
    return moonth_return;
    }

    获得日期

    //获得日期函数
    //输入值是日期位置的地址
    //返回值是 整型的10进制两位数
    int Get_Day(char *d)
    {
    int day_return;
    day_return = atoi(d)/1000000;   //取日期
    
    return day_return;
    }

    获得时间

    //获得时间
    //输入值是时间的位置的地址
    //返回值是 整型的10进制的时间总秒数
    int Get_Times(char *h, char *m, char *s)
    {
    int time_return;
    int hour_return;
    int min_return;
    int sec_return;
    
    hour_return = atoi(h)/10000;  //取小时
    min_return = atoi(m)/100;   //取分钟
    sec_return = atoi(s);   //取秒数
    
    time_return = hour_return*3600 + min_return*60 + sec_return;   //转换成总秒数
    
    return time_return;
    }

    完整解析过程

    我的整个处理时间的代码如下:

    //定义时间存储的全局变量(也可以定义成结构体)
    __IO uint32_t TIMES = 0;
    __IO uint32_t YEARS = 2019;
    __IO uint32_t MOONS = 1;
    __IO uint32_t DAYS = 1;
    __IO uint32_t WEEKS = 0;
    
    //获取网络时间并解析给系统
    void GET_Net_Time(void)
    {
    char *data_pt;
    char *day_string;
    char *moon_string;
    char *year_string;
    char *hour_string;
    char *minute_string;
    char *second_string;
    
    RT_Send_String(USART2, ESP_TIME_INFO);  //发送GET请求
    
    while(!(ESP_RX_STATE > 0));  //判断接收标志
    data_pt = strstr((const char *) ESP_RX_BUF.buf,(const char *)"sysTime1");   //寻找到时间结果的地址
    ESP_RX_STATE --;
    
    if(data_pt != NULL)
    {
    day_string = data_pt + DAYS_ADD_DRES;    //日期地址
    moon_string = data_pt + MOON_ADD_DRES;   //月份地址
    year_string = data_pt + YERA_ADD_DRES;   //年份地址
    hour_string = data_pt + HOURS_ADD_DRES;  //小时地址
    minute_string = data_pt + MINUTES_ADD_DRES;  //分钟地址
    second_string = data_pt + SECONDS_ADD_DRES;   //秒中地址
    
    //将时间信息传递给全局变量
    DAYS = Get_Day(day_string);
    MOONS = Get_Moonth(moon_string);
    YEARS = Get_Year(year_string);
    TIMES = Get_Times(hour_string, minute_string, second_string);
    }
    else
    {
    printf("get net time failed!\r\n");
    }
    }
    
    //获得年函数(以年开始的字符串长度过长,所以使用不同的方法)
    //输入值是年位置的地址
    //返回值是 整型的10进制四位数
    int Get_Year(char *y)
    {
    int year_return;
    char *year_temp;
    char year[5] = {0};
    char i;
    //年的获取需要提取一次字符串,否则无法读取
    year_temp = y;
    for(i = 0; i<4; i++)
    {
    year[i] = *year_temp;
    year_temp ++;
    }
    
    year_return =  atoi(&year[0]);
    return year_return;
    }
    
    //获得月份函数
    //输入值是月份位置的地址
    //返回值是 整型的10进制两位数
    int Get_Moonth(char *m)
    {
    int moonth_return;
    moonth_return = atoi(m)/100000000;   //取月份
    return moonth_return;
    }
    
    //获得日期函数
    //输入值是日期位置的地址
    //返回值是 整型的10进制两位数
    int Get_Day(char *d)
    {
    int day_return;
    day_return = atoi(d)/1000000;   //取日期
    
    return day_return;
    }
    
    //获得时间
    //输入值是时间的位置的地址
    //返回值是 整型的10进制的时间总秒数
    int Get_Times(char *h, char *m, char *s)
    {
    int time_return;
    int hour_return;
    int min_return;
    int sec_return;
    
    hour_return = atoi(h)/10000;  //取小时
    min_return = atoi(m)/100;   //取分钟
    sec_return = atoi(s);   //取秒数
    
    time_return = hour_return*3600 + min_return*60 + sec_return;   //转换成总秒数
    
    return time_return;
    }

    如此,所有的数据解析完毕,剩下的就是使用啦,具体怎么显示根据自己的方法实现。

    • 点赞 2
    • 收藏
    • 分享
    • 文章举报
    qq_一串随机码 发布了3 篇原创文章 · 获赞 19 · 访问量 5841 私信 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: