HTTP应用——上传(POST)数据到服务器,从服务器下载(GET)文件报文

前言

HTTP协议是一个简单的请求-响应协议,它通常运行在TCP之上,传输端口一般为80。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII码形式给出;在报文的可读性和调试性上有很大的优势。现在互联网大行其道,HTTP可以说是无处不在(HTTPS就是HTTP的TLS/SSL的加密传输形式,这种方式在认证上比较复杂)。下图展示了其处于网络的应用层:

那么物联网应用中的MCU想要进行HTTP的应用,需要如下两个步骤:

  1. 与服务器的80端口建立TCP连接。
  2. 使用HTTP的协议的报文格式传输和接收数据。

关于MCU和服务器建立TCP连接的方式有很多,例如使用WIFI透传模块等,你并不需要具体去了解TCP/IP的具体协议。本文主要讲的是使用HTTP的传输的时候报文,以及示例。如果模组自带HTTP/HTTPS协议栈那用起来将会更加便携。

HTTP报文

HTTP报文是简单的格式化的数据块。每条报文都包含一条来自客户端的请求,或者来自服务器的响应。它们由3个部分组成:

  • 对报文进行描述的起始行(start line)
  • 包含属性的首部块(header)
  • 可选的,包含数据的的主体(body)

下图就是一个HTTP服务器响应的报文内容:

例如向服务器请求一张图片的流程如下图所示:

常用的HTTP请求方法有:

常见的服务器返回的状态码有:

详细的HTTP报文解释可以参考《HTTP权威指南》。

GET方法:分片下载文件

例如我们要去下载 http://textfiles.com/programming/ymodem.txt 对应的 ymodem.txt 文件,但是MCU不能一次性接收全部数据,那么使用HTTP的按字节分片下载。

使用TCP client模拟的调试结果如下:

GET /programming/ymodem.txt HTTP/1.1
Host: textfiles.com
Connection: close
User-agent:Mozilla/5.0
Accept-language: en
Range: bytes=100-110


获取文档的100-110个字节。首部行一定要以一个空行结尾。MCU再根据回复的报文去解析数据即可。

POST方法:表单上传数据

表单的数据上传,这个要对应的服务器写好HTTP的接口。

例如我们要将数据  12345678901234  以表单的形式提交到服务器的HTTP接口。

示例如下所示:

[16:43:43.877]发→◇POST /http/index HTTP/1.1
HOST: 192.168.71.144
Accept:*/*
Content-Type:application/x-www-form-urlencoded
Content-Length:14
Cache-Control: no-cache

12345678901234□
[16:43:43.885]收←◆HTTP/1.1 200 OK
Server: nginx
Date: Fri, 29 Nov 2019 08:43:43 GMT
Content-Type: text/json;charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: 
Access-Control-Allow-Headers: 

46
{"msg":"POST Request OK data:{\"12345678901234\":\"\"}","status":true}
0


URL字符集

HTTP使用的是URL字符集,因为传输的报文中有时候不可避免的会包含一些二进制数据(非字母和字符时),为了表示这种数据在URL中提供一种转义的机制来表示这些字符。这种转义包含一个百分号(%),后面跟着两个表示字符ASCII码的十六进制数。示例如下:

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Linux C 下开发 HTTP 服务器时,可以使用开源的第三方库来解析 HTTP 请求,例如 `libcurl`、`libmicrohttpd` 等等。这些库提供了方便的接口来解析 HTTP 请求,包括解析 URL、解析 POST 数据等等。 以下是使用 `libmicrohttpd` 库来解析 HTTP 请求的示例代码: ```c #include <microhttpd.h> static int handle_request(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls) { // 解析 URL 和方法 if (strcmp(method, MHD_HTTP_METHOD_GET) == 0) { // 处理 GET 请求 const char *name = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "name"); const char *age = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "age"); // ... } else if (strcmp(method, MHD_HTTP_METHOD_POST) == 0) { // 处理 POST 请求 // 获取 POST 数据 char post_data[1024]; size_t post_data_size = MHD_get_connection_values(connection, MHD_POSTDATA_KIND, post_data, sizeof(post_data)); // 解析 POST 数据 const char *name = NULL; const char *age = NULL; char *pos = post_data; while (pos < post_data + post_data_size) { char *key = pos; char *value = strchr(pos, '='); if (value == NULL) { break; } *value++ = '\0'; char *end = strchr(value, '&'); if (end != NULL) { *end++ = '\0'; } else { end = post_data + post_data_size; } if (strcmp(key, "name") == 0) { name = value; } else if (strcmp(key, "age") == 0) { age = value; } pos = end; } // ... } // 返回响应 const char *response = "Hello, World!"; struct MHD_Response *resp = MHD_create_response_from_buffer(strlen(response), (void *) response, MHD_RESPMEM_PERSISTENT); MHD_add_response_header(resp, "Content-Type", "text/plain"); int ret = MHD_queue_response(connection, MHD_HTTP_OK, resp); MHD_destroy_response(resp); return ret; } int main() { struct MHD_Daemon *daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, 8080, NULL, NULL, &handle_request, NULL, MHD_OPTION_END); if (daemon == NULL) { printf("Failed to start daemon\n"); return 1; } getchar(); MHD_stop_daemon(daemon); return 0; } ``` 在以上示例代码中,`handle_request` 函数用于处理 HTTP 请求。在函数中,首先根据请求的方法来解析 URL 或 POST 数据。对于 GET 请求,可以使用 `MHD_lookup_connection_value` 函数来解析 URL 参数;对于 POST 请求,可以使用 `MHD_get_connection_values` 函数来获取 POST 数据,然后自行解析 POST 数据。 需要注意的是,在解析 POST 数据时,需要手动解析 POST 数据的格式。通常情况下,POST 数据的格式为 `key1=value1&key2=value2&...`,需要根据这个格式来解析 POST 数据。 最后,需要根据请求返回相应的响应。在示例代码中,返回了一个简单的响应 "Hello, World!"。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值