简介

        HTTP是Hypertext Transfer Protocol(超文本传输协议)的缩写。超文本传输协议是一种用于分布式、协作式和超媒体信息系统的应用层协议,是因特网上应用最为广泛的一种网络传输协议,所有的 WWW 文件都必须遵守这个标准。

        HTTP 是为客户端服务器之间的通信而设计的,但也可以用于其他目的。

        HTTP 是一个基于 TCP/IP 通信协议来传递数据的(HTML 文件、图片文件、查询结果等)。

HTTP协议的请求及响应方式设计如下:

        从图中可以看出,服务器端响应客户端请求后立刻断开连接,连接不会维持很久,即使同一个客户端再次发送请求,服务端也无法辨认出是否是原先的那个客户端发出的请求,会以相同的方式处理新的请求。

HTTP三点注意事项:

        HTTP是无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

        HTTP是媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。

        HTTP是无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

HTTP请求

        HTTP请求是客户端服务端发送请求消息,请求消息可以分为请求行(request line)消息头(header)消息体(message)三个部分.

        请求行请求方法字段URL字段HTTP协议版本字段3个字段组成,它们用空格分隔。例如,GET /index.html HTTP/1.1。

        根据HTTP标准,HTTP请求可以使用多种请求方法。

HTTP1.0定义了三种请求方法: GET, POSTHEAD方法。

HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

目前大部分只支持GET和POST方法。GET用于请求数据POST主要用于传输数据

 消息头包括一些访问的域名、用户代理、Cookie等信息;

Header

解释

示例

Accept

指定客户端能够接收的内容类型

Accept: text/plain, text/html,*/*

Accept-Charset

浏览器可以接受的字符编码集。

Accept-Charset: iso-8859-5

Accept-Encoding

指定浏览器可以支持的web服务器返回内容压缩编码类型。

Accept-Encoding: compress, gzip

Accept-Language

浏览器可接受的语言

Accept-Language: en,zh

Accept-Ranges

可以请求网页实体的一个或者多个子范围字段

Accept-Ranges: bytes

Authorization

HTTP授权的授权证书

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Cache-Control

指定请求和响应遵循的缓存机制

Cache-Control: no-cache

Connection

表示是否需要持久连接。(HTTP 1.1默认进行持久连接)

Connection: keep-alive

Cookie

HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。

Cookie: $Version=1; Skin=new;

Content-Length

请求的内容长度

Content-Length: 348

Content-Type

请求的与实体对应的MIME信息

Content-Type: application/x-www-form-urlencoded

Date

请求发送的日期和时间

Date: Tue, 15 Nov 2010 08:12:31 GMT

Expect

请求的特定的服务器行为

Expect: 100-continue

From

发出请求的用户的Email

From: user@email.com

Host

指定请求的服务器的域名和端口号

Host: www.zcmhi.com

If-Match

只有请求内容与实体相匹配才有效

If-Match: “737060cd8c284d8af7ad3082f209582d”

If-Modified-Since

如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码

If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT

If-None-Match

如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变

If-None-Match: “737060cd8c284d8af7ad3082f209582d”

If-Range

如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag

If-Range: “737060cd8c284d8af7ad3082f209582d”

If-Unmodified-Since

只在实体在指定时间之后未被修改才请求成功

If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT

Max-Forwards

限制信息通过代理和网关传送的时间

Max-Forwards: 10

Pragma

用来包含实现特定的指令

Pragma: no-cache

Proxy-Authorization

连接到代理的授权证书

Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Range

只请求实体的一部分,指定范围

Range: bytes=500-999

Referer

先前网页的地址,当前请求网页紧随其后,即来路

Referer: http://www.zcmhi.com/archives/71.html

TE

客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息

TE: trailers,deflate;q=0.5

Upgrade

向服务器指定某种传输协议以便服务器进行转换(如果支持)

Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11

User-Agent

User-Agent的内容包含发出请求的用户信息

User-Agent: Mozilla/5.0 (Linux; X11)

Via

通知中间网关或代理服务器地址,通信协议

Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)

Warning

关于消息实体的警告信息

Warn: 199 Miscellaneous warning

        消息体就是请求的数据,仅在POST方式请求时候输入。

HTTP响应

        HTTP响应是指服务端根据客户端发送的请求中的动作要求做出具体的动作,然后将结果返回给客户端。 HTTP响应消息可以分为状态行头信息消息体三个部分;状态行含有请求的状态信息,这是其与请求消息相比最大的区别。

 

 响应的头信息包括如下:

Header

解释

示例

Accept-Ranges

表明服务器是否支持指定范围请求及哪种类型的分段请求

Accept-Ranges: bytes

Age

从原始服务器到代理缓存形成的估算时间(以秒计,非负)

Age: 12

Allow

对某网络资源的有效的请求行为,不允许则返回405

Allow: GET, HEAD

Cache-Control

告诉所有的缓存机制是否可以缓存及哪种类型

Cache-Control: no-cache

Content-Encoding

web服务器支持的返回内容压缩编码类型。

Content-Encoding: gzip

Content-Language

响应体的语言

Content-Language: en,zh

Content-Length

响应体的长度

Content-Length: 348

Content-Location

请求资源可替代的备用的另一地址

Content-Location: /index.htm

Content-MD5

返回资源的MD5校验值

Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==

Content-Range

在整个返回体中本部分的字节位置

Content-Range: bytes 21010-47021/47022

Content-Type

返回内容的MIME类型

Content-Type: text/html; charset=utf-8

Date

原始服务器消息发出的时间

Date: Tue, 15 Nov 2010 08:12:31 GMT

ETag

请求变量的实体标签的当前值

ETag: “737060cd8c284d8af7ad3082f209582d”

Expires

响应过期的日期和时间

Expires: Thu, 01 Dec 2010 16:00:00 GMT

Last-Modified

请求资源的最后修改时间

Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT

Location

用来重定向接收方到非请求URL的位置来完成请求或标识新的资源

Location: http://www.zcmhi.com/archives/94.html

Pragma

包括实现特定的指令,它可应用到响应链上的任何接收方

Pragma: no-cache

Proxy-Authenticate

它指出认证方案和可应用到代理的该URL上的参数

Proxy-Authenticate: Basic

refresh

应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持)

Refresh: 5; url=http://www.zcmhi.com/archives/94.html

Retry-After

如果实体暂时不可取,通知客户端在指定时间之后再次尝试

Retry-After: 120

Server

web服务器软件名称

Server: Apache/1.3.27 (Unix) (Red-Hat/Linux)

Set-Cookie

设置Http Cookie

Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1

Trailer

指出头域在分块传输编码的尾部存在

Trailer: Max-Forwards

Transfer-Encoding

文件传输编码

Transfer-Encoding:chunked

Vary

告诉下游代理是使用缓存响应还是从原始服务器请求

Vary: *

Via

告知代理客户端响应是通过哪里发送的

Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)

Warning

警告实体可能存在的问题

Warning: 199 Miscellaneous warning

WWW-Authenticate

表明客户端请求实体应该使用的授权方案

WWW-Authenticate: Basic

相关函数介绍

http_get() 从服务器中读取数据

GET方法要求服务器将URL定位的资源放在响应报文的数据部分,回送给客户端

函数原型

HTTPCLIENT_RESULT httpclient_get(httpclient_t *client, char *url, httpclient_data_t *client_data);

参数:

Client

指向http_client的指针

typedef struct {

    int socket;                     /**< Socket ID. */

    int remote_port;                /**< HTTP or HTTPS port. */

    int response_code;              /**< Response code. */

    char *header;                   /**< Request custom header. */

    char *auth_user;                /**< Username for basic authentication. */

    char *auth_password;            /**< Password for basic authentication. */

    bool is_http;                   /**< Http connection? if 1, http; if 0, https. */

#ifdef MTK_HTTPCLIENT_SSL_ENABLE

    const char *server_cert;        /**< Server certification. */

    const char *client_cert;        /**< Client certification. */

    const char *client_pk;          /**< Client private key. */

    int server_cert_len;            /**< Server certification lenght, server_cert buffer size. */

    int client_cert_len;            /**< Client certification lenght, client_cert buffer size. */

    int client_pk_len;              /**< Client private key lenght, client_pk buffer size. */

    void *ssl;                      /**< Ssl content. */

#endif

#ifdef HTTPCLIENT_REDIRECT

    int redirect_times;             /**< Current redirection times. */

#endif

} httpclient_t;

Url:

就是平时所说的“网址”

client_data

/** @brief   This structure defines the HTTP data structure.  */

typedef struct {

    bool is_more;                /**< Indicates if more data needs to be retrieved. */

    bool is_chunked;             /**< Response data is encoded in portions/chunks.*/

    int retrieve_len;            /**< Content length to be retrieved. */

    int response_content_len;    /**< Response content length. */

    int content_block_len;       /**< The content length of one block. */

    int post_buf_len;            /**< Post data length. */

    int response_buf_len;        /**< Response body buffer length. */

    int header_buf_len;          /**< Response head buffer lehgth. */

    char *post_content_type;     /**< Content type of the post data. */

    char *post_buf;              /**< User data to be posted. */

    char *response_buf;          /**< Buffer to store the response body data. */

    char *header_buf;            /**< Buffer to store the response head data. */

    // Range Feature

    int range_enable;            /**< Indicates use range request or not. */

    int range_begin;             /**< The source begin if range_enable is 1. */

    int range_end;               /**< The source end if range_enable is 1. */

    int range_len;               /**< The source length if range_enable is 1. */

} httpclient_data_t;

        该参数中需要关注的是response_bufresponse_buf_len参数。因为需要获取Http数据,所以参数需要有接受数据的缓冲区以及长度。

返回值:

/** @brief   This enumeration defines the API return type.  */

typedef enum {

    HTTPCLIENT_ERROR_PARSE = -6,           /**< A URL parse error occurred. */

    HTTPCLIENT_UNRESOLVED_DNS = -5,        /**< Could not resolve the hostname. */

    HTTPCLIENT_ERROR_PRTCL = -4,           /**< A protocol error occurred. */

    HTTPCLIENT_ERROR = -3,                 /**< An unknown error occurred. */

    HTTPCLIENT_CLOSED = -2,                /**< Connection was closed by a remote host. */

    HTTPCLIENT_ERROR_CONN = -1,            /**< Connection failed. */

    HTTPCLIENT_OK = 0,                     /**< The operation was successful. */

    HTTPCLIENT_RETRIEVE_MORE_DATA = 1      /**< More data needs to be retrieved. */

} HTTPCLIENT_RESULT;

实例:

char *url = "https://www.baidu.com/";

httpclient_t client = {0};

httpclient_data_t client_data = {0};

char *buf = NULL;

buf = pvPortMalloc(BUF_SIZE);

if (buf == NULL) {

    printf("Malloc failed.\r\n");

     return;

}

memset(buf, 0, sizeof(buf));

client_data.response_buf = buf;  //Sets a buffer to store the result.

client_data.response_buf_len = BUF_SIZE;  //Sets the buffer size.

httpclient_get(&client, url, &client_data);

printf("Data received: %s\r\n", client_data.response_buf);

http_post() 推送数据到服务器

该函数向指定资源提交数据进行处理。

函数原型:

HTTPCLIENT_RESULT httpclient_post(httpclient_t *client, char *url, httpclient_data_t *client_data);

参数:

Client:

同上

Url:

网址

client_data:

这里需要注意char *post_content_type参数

Content-type的类型

常见的媒体格式类型:

        text/html : HTML格式

        text/plain :纯文本格式      

        text/xml :  XML格式

        image/gif :gif图片格式    

        image/jpeg :jpg图片格式

        image/png:png图片格式
以applicaton开头的媒体类型:

    application/json    : JSON数据格式

    application/xhtml+xml :XHTML格式

    application/xml     : XML数据格式

    application/atom+xml  :Atom XML聚合格式    

    application/pdf       :pdf格式  

    application/javascript :js格式

    application/msword  : Word文档格式

    application/octet-stream : 二进制流数据(如常见的文件下载)

    application/x-www-form-urlencoded :form表单默认的数据格式类型,form表单数据被编码为key/value格式发送到服务器。

返回值:

/** @brief   This enumeration defines the API return type.  */

typedef enum {

    HTTPCLIENT_ERROR_PARSE = -6,           /**< A URL parse error occurred. */

    HTTPCLIENT_UNRESOLVED_DNS = -5,        /**< Could not resolve the hostname. */

    HTTPCLIENT_ERROR_PRTCL = -4,           /**< A protocol error occurred. */

    HTTPCLIENT_ERROR = -3,                 /**< An unknown error occurred. */

    HTTPCLIENT_CLOSED = -2,                /**< Connection was closed by a remote host. */

    HTTPCLIENT_ERROR_CONN = -1,            /**< Connection failed. */

    HTTPCLIENT_OK = 0,                     /**< The operation was successful. */

    HTTPCLIENT_RETRIEVE_MORE_DATA = 1      /**< More data needs to be retrieved. */

} HTTPCLIENT_RESULT;

实例:

char *url = "https://api.mediatek.com/mcs/v2/devices/D0n2yhrl/datapoints.csv";

char *header = "deviceKey:FZoo0S07CpwUHcrt\r\n";

char *content_type = "text/csv";

char *post_data = "1,,I am string!";

httpclient_t client = {0};

httpclient_data_t client_data = {0};

char *buf = NULL;

buf = pvPortMalloc(BUF_SIZE);

if (buf == NULL) {

printf("Malloc failed.\r\n");

    return;

}

memset(buf, 0, sizeof(buf));

client_data.response_buf = buf;  //Sets a buffer to store the result.

client_data.response_buf_len = BUF_SIZE;  //Sets the buffer size.

httpclient_set_custom_header(&client, header);  //Sets the custom header if needed.

client_data.post_buf = post_data;  //Sets the user data to be posted.

client_data.post_buf_len = strlen(post_data);  //Sets the post data length.

client_data.post_content_type = content_type;  //Sets the content type.

httpclient_post(&client, url, &client_data);

printf("Data received: %s\r\n", client_data.response_buf);

        这里httpclient_set_custom_header(&client, header)函数是配置请求头,通常用于http的请求鉴权

        注:POST的安全性要比GET的安全性高。注意:这里所说的安全性和上面GET提到的“安全”不是同个概念。上面“安全”的含义仅仅是不作数据修改,而这里安全的含义是真正的Security的含义,比如:通过GET提交数据,用户名和密码将明文出现在URL上,因为(1)登录页面有可能被浏览器缓存, (2)其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了。而通过POST提交数据是经过加密的。

httpclient_connect()

与远程的URL建立一个HTTP连接

函数原型

HTTPCLIENT_RESULT httpclient_connect(httpclient_t *client, char *url);

参数:

client:

HTTP客户端描述符,当与远程URL建立链接成功后,作为参数被其他函数调用。结构体原型如下:

/** @brief   This structure defines the httpclient_t structure.  */
typedef struct {
    int socket;                     /**< Socket ID. */
    int remote_port;                /**< HTTP or HTTPS port. */
    int response_code;              /**< Response code. */
    char *header;                   /**< Request custom header. */
    char *auth_user;                /**< Username for basic authentication. */
    char *auth_password;            /**< Password for basic authentication. */
    bool is_http;                   /**< Http connection? if 1, http; if 0, https. */
#ifdef MTK_HTTPCLIENT_SSL_ENABLE
    const char *server_cert;        /**< Server certification. */
    const char *client_cert;        /**< Client certification. */
    const char *client_pk;          /**< Client private key. */
    int server_cert_len;            /**< Server certification lenght, server_cert buffer size. */
    int client_cert_len;            /**< Client certification lenght, client_cert buffer size. */
    int client_pk_len;              /**< Client private key lenght, client_pk buffer size. */
    void *ssl;                      /**< Ssl content. */
#endif
#ifdef HTTPCLIENT_REDIRECT
    int redirect_times;             /**< Current redirection times. */
#endif
} httpclient_t;

url:

需要建立HTTP连接的远程服务器域名

返回值:

typedef enum {
    HTTPCLIENT_ERROR_PARSE = -6,           /**< A URL parse error occurred. */
    HTTPCLIENT_UNRESOLVED_DNS = -5,        /**< Could not resolve the hostname. */
    HTTPCLIENT_ERROR_PRTCL = -4,           /**< A protocol error occurred. */
    HTTPCLIENT_ERROR = -3,                 /**< An unknown error occurred. */
    HTTPCLIENT_CLOSED = -2,                /**< Connection was closed by a remote host. */
    HTTPCLIENT_ERROR_CONN = -1,            /**< Connection failed. */
    HTTPCLIENT_OK = 0,                     /**< The operation was successful. */
    HTTPCLIENT_RETRIEVE_MORE_DATA = 1      /**< More data needs to be retrieved. */
} HTTPCLIENT_RESULT;

成功时返回0,其余值对应错误类型。

实例:
 

#define HTTPS_MTK_CLOUD_POST_URL    "https://api.mediatek.com/mcs/v2/devices/D0n2yhrl/datapoints.csv"

httpclient_t client = {0};

char *post_url = HTTPS_MTK_CLOUD_POST_URL;

HTTPCLIENT_RESULT ret = HTTPCLIENT_ERROR_CONN;

ret = httpclient_connect(&client, post_url);

    if (ret < 0)                    

        goto fail;

httpclient_send_request()

向远程服务器发送HTTP请求(GET或POST)。

函数原型:

HTTPCLIENT_RESULT httpclient_send_request(httpclient_t *client, char *url, int method, httpclient_data_t *client_data);

参数:

client,客户端描述符

httpclient_connect()函数建立连接时的客户端描述符。

url,远程URL

method,方式,类型如下:

typedef enum {
    HTTPCLIENT_GET,
    HTTPCLIENT_POST,
    HTTPCLIENT_PUT,
    HTTPCLIENT_DELETE,
    HTTPCLIENT_HEAD
} HTTPCLIENT_REQUEST_TYPE;

client_data,数据缓冲区,结构体原型如下:

typedef struct {
    bool is_more;                /**< Indicates if more data needs to be retrieved. */
    bool is_chunked;             /**< Response data is encoded in portions/chunks.*/
    int retrieve_len;            /**< 某次请求剩余数据长度Content length to be retrieved. */
    int response_content_len;    /**< Response content length. */
    int content_block_len;       /**< The content length of one block. */
    int post_buf_len;            /**< Post data length. */
    int response_buf_len;        /**< Response body buffer length. */
    int header_buf_len;          /**< Response head buffer lehgth. */
    char *post_content_type;     /**< Content type of the post data. */
    char *post_buf;              /**< User data to be posted. */
    char *response_buf;          /**< Buffer to store the response body data. */
    char *header_buf;            /**< Buffer to store the response head data. */
    // Range Feature
    int range_enable;            /**< Indicates use range request or not. */
    int range_begin;             /**< The source begin if range_enable is 1. */
    int range_end;               /**< The source end if range_enable is 1. */
    int range_len;               /**< The source length if range_enable is 1. */
} httpclient_data_t;

        每次的GET或POST之前,都需要配置好client_data。配置好后,后续的GET或POST操作,结果会直接到client_data中。

返回值:

typedef enum {
    HTTPCLIENT_ERROR_PARSE = -6,           /**< A URL parse error occurred. */
    HTTPCLIENT_UNRESOLVED_DNS = -5,        /**< Could not resolve the hostname. */
    HTTPCLIENT_ERROR_PRTCL = -4,           /**< A protocol error occurred. */
    HTTPCLIENT_ERROR = -3,                 /**< An unknown error occurred. */
    HTTPCLIENT_CLOSED = -2,                /**< Connection was closed by a remote host. */
    HTTPCLIENT_ERROR_CONN = -1,            /**< Connection failed. */
    HTTPCLIENT_OK = 0,                     /**< The operation was successful. */
    HTTPCLIENT_RETRIEVE_MORE_DATA = 1      /**< More data needs to be retrieved. */
} HTTPCLIENT_RESULT;

成功时返回0,其余值对应错误类型。

实例:

#define HTTP_GET_URL    "http://www.aliyun.com/"

char *get_url = HTTP_GET_URL;

HTTPCLIENT_RESULT ret;    

httpclient_t client = {0};

char *buf;

httpclient_data_t client_data = {0};

buf = pvPortMalloc(BUF_SIZE);


client_data.response_buf = buf;

client_data.response_buf_len = 128;

ret = httpclient_send_request(&client, get_url, HTTPCLIENT_GET, &client_data);

        if (ret < 0)            

            goto fail;

httpclient_recv_response()

接收上次请求的响应。

函数原型:

HTTPCLIENT_RESULT httpclient_recv_response(httpclient_t *client, httpclient_data_t *client_data);

参数:

client,客户端描述符

httpclient_connect()函数建立连接时的客户端描述符。

client_data,数据缓冲区。

返回值:

typedef enum {
    HTTPCLIENT_ERROR_PARSE = -6,           /**< A URL parse error occurred. */
    HTTPCLIENT_UNRESOLVED_DNS = -5,        /**< Could not resolve the hostname. */
    HTTPCLIENT_ERROR_PRTCL = -4,           /**< A protocol error occurred. */
    HTTPCLIENT_ERROR = -3,                 /**< An unknown error occurred. */
    HTTPCLIENT_CLOSED = -2,                /**< Connection was closed by a remote host. */
    HTTPCLIENT_ERROR_CONN = -1,            /**< Connection failed. */
    HTTPCLIENT_OK = 0,                     /**< The operation was successful. */
    HTTPCLIENT_RETRIEVE_MORE_DATA = 1      /**< More data needs to be retrieved. */
} HTTPCLIENT_RESULT;

成功时返回0,其余值对应错误类型。

实例:

#define HTTP_GET_URL    "http://www.aliyun.com/"

char *get_url = HTTP_GET_URL;

HTTPCLIENT_RESULT ret;    

httpclient_t client = {0};

char *buf;

httpclient_data_t client_data = {0};

buf = pvPortMalloc(BUF_SIZE);


client_data.response_buf = buf;

client_data.response_buf_len = 128;

do {            
            // Receive response from server
            ret = httpclient_recv_response(&client, &client_data);
            if (ret < 0)
                goto fail;
            count += strlen(client_data.response_buf);
            printf("data received: %s", client_data.response_buf);
   } while (ret == HTTPCLIENT_RETRIEVE_MORE_DATA);

httpclient_close()

关闭HTTP连接。

函数原型:

void httpclient_close(httpclient_t *client);

参数:

client,客户端描述符

httpclient_connect()函数建立连接时的客户端描述符。

返回值:

实例:

httpclient_t client = {0};

httpclient_close(&client);

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐