esp8266 下载文件后如何去除HTTP头

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhejfl/article/details/79472542

参考文章:https://www.cnblogs.com/arnoldlu/p/6497837.html

通过HTTP 发出GET请求从服务器下载文件,特别是Bin文件等二进制文件。在TCP接收回调函数中,利用os_printf("%s",pdata)试图从串口输出GET的内容,但由于在二进制文件中可能存在\0,而导致输出中止,os_printf() 用于输出字符串,而字符串遇到'\0'结束。因此采用os_printf()以不合适,采用uart0_tx_buffer 输出指定数据缓存中指定长度的数据。

对于本文的主题,参考文章提到的http-parser和fast-http是解析HTTP协议两个不错的版本。本文以http-parser为研究对象。

对于发送GET请求request和解析 Response HTTP头,了解请求和响应时HTTP的组成是第一步。

HTTP请求和响应格式

Request格式——请求头(向服务器发出请求用)

<Request-line>                                METHOD /path-to-resource HTTP/Version-number                          

<headers>                                        Header-Name-1:value

                                                          Header-Name-2:value

<blank line>                                      空行

[<request-body>]                             可选的其他任意数据

说明:第一行必须是一个请求行(request-line),用来说明请求类型,要访问的资源以及所用到的HTTP版本;

   第一行中Method 是请求方法-常用的有GET、POST。对于HTTP1.1目前支持7钟请求方法:GET/POST/HEAD/OPTION/PUT/DELETE/TRACE。他们的不同之处,点击此处

紧接的是一个header 小节, 用来说明服务器要使用的附加信息

之后,必须是一个空行

最后,是可选的其他任意数据---称为主体(body)

例子:

GET/sample.jsp HTTP/1.1      第一部分说明这是一个GET请求, 第二步峰说明资源在根目录的/sample.jsp ,版本为HTTP1.1
Accept:image/gif.image/jpeg.*/*      请求的第一个首部Header, 浏览器支持的EMIME类型分别是。。。                       
Accept-Language:zh-cn                    浏览器支持的语言分别是:简体中文
Connection:Keep-Alive                            该Header通常设置为Keep-Alive 表示客户端和服务器端是持久连接
Host:www.google.cn                                     Host 这一Header指出请求的目的地是:www.google.cn
User-Agent:Mozila/4.0(compatible:MSIE5.01:Windows NT5.0)    

Accept-Encoding:gzip,deflate.           浏览器支持的压缩编码是给IP和deflate

User-Agent这一header指出服务器端和客户端脚本均访问她,她是浏览器类型检测逻辑的重要基础,该信息由你的浏览器来定义,并且在每个请求中主动发送;  这是使用的额代理是Mozilla/4.0(域名)

第三部分是空行,即使不存在请求主题,这个空行也是必需的。

这个空行,非常重要,她表示请求头已经结束,接下去的是请求正文(body)。请求正文中可以包含客户提交的查询字符串信息。

例如username=fangle&password=1234

上面是我们发出请求的基础,在ESP8266中发出请求一定不能出错,这一步一出错,后面就OVER了。下面进行Respost头的分析,这是我们解析Recv的应答头的基础。

HTTP 响应格式

<status-line>                        Http/version-number        status code  message

<headers>                            header-Name-1:value

<blank line>               也有

[<respones-body> ]             Optional Response body

第一行是状态行,由HTTP协议版本号,状态码、状态消息三部分组成,各部分以空格隔开。

    HTTP/version-number表示HTTP协议的版本号,   status-code 是数字形式的状态码 mesage是相应的状态描述。

    HTTP/1.1中定义了5类状态码,状态码由三位数字组成,第一个数字表示响应的类别。

    1XX   提示信息 --表示请求已被成功接收,继续处理

    2XX  成功-表示请求已被成功接收,理解,接收

    3XX 重定向- 请求有语法错误或请求无法实现

    4XX  客户端错误 -  请求有语法错误或请求无法实现

    5XX  服务器端错误 -   服务器未能实现合法的请求

    200 OK:最常见的就是成功响应状态码200了, 这表明该请求被成功地完成,所请求的资源发送回客户端。

    404  Not Found :请求资源不存在,例如输出URL错误。

    对于重定向而言,就是新的URL会在response 中的Location中返回,浏览器将会自动使用新的URL发出新的Request。

第二行开始是Response的Header部分

其中对于我们解析下载的文件解析有用的Header为Content-Length: Content-Length 实体包头域用来指明正文body的长度,以字节方式存储的十进制数字来表示,也就是一个数字符号占一个字节,用于对应的ASCII码存储传输。

Content-Type实体报头域用来指明发送给接收者的实体正文的媒体类型。如Content-Type:text/html;charset=ISO-8859-1

缺图

其他Header部分以后补充

在Header与正文(Body)之间也有一个空行,这也是必需的。

这样根据这一特点,有人也用在其中找到"\r\n\r\n"来正文部分。这也是可行一个法子。

接下去,我们就来探究一下http-parser来解析Http的内容。 HTTP-Parser 是用C语言写的HTTP信息解析器。它可用于解析请求和响应。该解析器设计增强HTTP应用的性能。

再接下去,讲解下HTTP-Praser的使用。在每个TCP连接中使用一个http_parser对象,用http_parser_init()初始化她以及设置回调。

当socket(套接字)接收到Response时,执行解析器并检查错误。

http_parser_execute(parser, &settings, buf, recved); 执行解析过程,其原型

/**********

*执行解析器,返回解析的字节,Sets parse->http_errno 

*input  parse指向解析器对象;  settings指向 回调函数结构体设置,data指向待解析的数据, len:带解析的长度

*****************/

size_t http_parser_execute(http_parser *parser,

                           const http_parser_settings *settings,
                           const char *data,
                           size_t len);

对于结构体http_parser_settings

struct http_parser_settings {
  http_cb      on_message_begin;
  http_data_cb on_url;
  http_data_cb on_status;
  http_data_cb on_header_field;
  http_data_cb on_header_value;
  http_cb      on_headers_complete;
  http_data_cb on_body;
  http_cb      on_message_complete;
  /* When on_chunk_header is called, the current chunk length is stored
   * in parser->content_length.
   */
  http_cb      on_chunk_header;
  http_cb      on_chunk_complete;

};   http_cb   和 http_data_cb都是函数指针类型,如下所示

typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);

typedef int (*http_cb) (http_parser*);


代码一般如下所示:

int on_header_field(http_parser* _, const char* at, size_t length) {
  (void)_;
  printf("Header field: %.*s\n", (int)length, at);
  return 0;
}

int on_header_value(http_parser* _, const char* at, size_t length) {
  (void)_;
  printf("Header value: %.*s\n", (int)length, at);
  return 0;
}

//这两者对应输出

int on_body(http_parser* _, const char* at, size_t length) {
  (void)_;
  printf("Body: %.*s\n", (int)length, at);  //at就是所有的正文数据,以及lenght是其长度
  return 0;
}

static http_parser_settings settings_null =  //http_parser的回调函数,需要获取HEADER或者BODY信息,可以在这里面处理。

  {.on_message_begin = 0
  ,.on_header_field = on_header_field
  ,.on_header_value = on_header_value
  ,.on_url = 0
  ,.on_status = 0
  ,.on_body = on_body
  ,.on_headers_complete = 0
  ,.on_message_complete = 0
  };


在ESP8266 的接收回调函数中:

#include "http_parser.h"

static http_parser 8parser;

void espconn_recv_cb( void *arg, char *pdata, unsigned short len)

{

        struct espconn  *pesp_conn = arg;

        parase_recv(pdata, len);

}

 void  parase_recv(const char *buf, unsigned short len)

{

        int i;

     //   float start, end;

        size_t parsed;  //解析的字节数

        parser = (struct http_parser *)os_zalloc(http_parser);

        http_parser_init(parse,HTTP_RESPONSE); //初始化Parser 为Response类型

        parsed = http_parser_execute(parser, &settings_null, buf, len); 执行解析过程

        free(parser)

}


最后我们在讲讲那种偷懒的方法——找"\r\n\r\n"。

#include <stdlib>

        int  length=0;

        char *binContent= NULL;

         void  parase_recv(const char *buf, unsigned short len)

{

         char *PA;

         char *PB;

        char *PC;

        char strLength[32]={0};   

        if(!(*buf))  return;

         PA = buf;

        PB = os_strstr(PA,"Content-Length:")

        PC = os_strstr(PB,"\r\n");

       memcpy(strLength,PB, PC-PB);

      length = atoi(strLength);

      binContent = (char *)zalloc(length );

       PC = NULL;

     if(PC= os_strstr(PB,"\r\n\r\n"))

          PC +=os_strlen("\r\n\r\n");

    memcpy(binConten, PC, length);

        

}

对于http-paraser的代码解析,具体再下一章具体解释。


猜你喜欢

转载自blog.csdn.net/zhejfl/article/details/79472542