打印
[MM32软件]

MM32搭建Web服务器——POST指令

[复制链接]
636|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wowu|  楼主 | 2023-2-14 14:16 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
GET & POST的区别
如果你对服务器和浏览器的交互还没有概念的话呢,建议先看一下「Rose Island」山外多功能调试助手用作虚拟服务器。

可以看到,通过域名或是IP地址加载网页内容是默认通过GET请求,之后服务器与客户端的交互可以通过GET,也可以通过POST。

GET和POST的区别大致如下:

                                       GET                                            POST
可传递数据类型        ASCII文本(汉字有专门的方法转换)        不限,支持二进制文件
可传递的数据量        有限制(2048字节减去URL长度)        无限制
内容编码类型        application/x-www-form-urlencoded        application/x-www-form-urlencoded
                                                                                  或multipart/form-data
后退/刷新            回退后再次前进或刷新不会通知用户        数据会被再次提交
历史记录                      浏览器会记录全部内容                      浏览器只记录接收POST内容的URL但不记录POST的具体内容
典型应用                获取服务器上的资源,如url地址栏请求,下载        向服务器添加资源,如上传附件,提交表单

GET和POST还有一个区别就是TCP数据包的个数,GET产生一个数据包,POST产生两个数据包,分别放header和data。两者请求的过程如下:

GET请求过程:
浏览器请求tcp连接(第一次握手)
服务器答应进行tcp连接(第二次握手)
浏览器确认,并发送GET请求header和data(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
服务器返回200 OK响应
POST请求过程:
浏览器请求tcp连接(第一次握手)
服务器答应进行tcp连接(第二次握手)
浏览器确认,并发送POST请求header(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
服务器返回100 Continue响应
浏览器发送body中的数据
服务器返回200 OK响应
不过并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

我对GET和POST区别的理解呢,最重要的是上传表单的时候GET会将内容都显示到浏览器url地址上,安全性很差,而POST会将参数名和参数值放到body中,不会在浏览器url地址上显示出来。

举个栗子看一下:

GET请求

<!DOCTYPE HTML>
<html>

<head>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
    <title>用户登录 - MindMotion</title>
</head>

<body>
    <form action="login.cgi" method="GET" name="login">
        <label>
            <h1>用户账号登录</h1>
            <hr><br>
        </label>
            账&nbsp;&nbsp;号:<input type="text" placeholder="请输入账号名" name="username" required><br>
            密&nbsp;&nbsp;码:<input type="password" placeholder="请输入密码" name="password" required><br><br>
            <input id="submit" type="submit" name="checkinSubmit" value="login">
    </form>
</body>
</html>



点击submit之后可以看到:



表单数据以param1=param1_value&param2=param2_vlaue的形式添加在url后面,以?分割,每个Param之间用&分割。

POST请求

<!DOCTYPE HTML>
<html>

<head>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
    <title>用户登录 - MindMotion</title>
</head>

<body>
    <form action="login.cgi" method="POST" name="login">
        <label>
            <h1>用户账号登录</h1>
            <hr><br>
        </label>
            账&nbsp;&nbsp;号:<input type="text" placeholder="请输入账号名" name="username" required><br>
            密&nbsp;&nbsp;码:<input type="password" placeholder="请输入密码" name="password" required><br><br>
            <input id="submit" type="submit" name="checkinSubmit" value="login">
    </form>
</body>
</html>



点击submit之后可以看到:



表单数据封装在body中,url中只显示对应的action。

POST请求在CGI中的实现
介绍一下整个项目使用的软硬件环境:

硬件环境:MM32F3277、网线

软件环境:IAR、FreeRTOS、LWIP、makefsfile.exe

如果对CGI和SSI接口不熟悉的话,可以看一下「Rose Island」MM32搭建Web服务器——SSI和CGI接口,里面包括了GET请求在CGI中的实现方法。

先说一下浏览器和MM32服务器通过POST指令请求的过程:

浏览器和TCP建立连接后,函数http_recv()接收浏览器的请求数据
MM32调用http_parse_request()函数提取接收到的字符串中是GET指令还是POST指令
调用http_post_request处理POST请求
调用httpd_post_begin处理header部分的uri
调用httpd_post_rxpbuf处理接收数据长度
调用httpd_post_receive_data处理body部分的数据
调用httpd_handle_post_finished,在这里调用http_find_file
之后的过程就和上一篇写的一样啦
在LWIP中,默认使用GET方法,所以使用POST指令需要自己写几个函数。

首先得先将这个POST定义修改为1

#define LWIP_HTTPD_SUPPORT_POST  1


也需要关心一下可传递数据的大小,文件数据一般是1514字节一帧数据地发送给板端

#define PBUF_POOL_BUFSIZE 1524


虽然LWIP中没有写POST的相关函数,但在httpd.h中定义了三个函数,分别是httpd_post_begin,httpd_post_receive_data,httpd_post_finished

httpd_post_begin用于初始化POST数据接收功能,获取uri,就是header部分

err_t httpd_post_begin(void *connection, const char *uri,
                       const char *http_request,u16_t http_request_len,
                       int content_len, char *response_uri,
                       u16_t response_uri_len, u8_t *post_auto_wnd)
{
    memset(http_uri_buf,0,sizeof(http_uri_buf));
    strcpy(response_uri,uri);

    return ERR_OK;
}


httpd_post_receive_data用于接收数据内容,就是body部分,分为params和param_vals

方法一:

在uri后面加上?然后加上*p中的param1=param1_val & param2=param2_val,在这里人为地把POST转成GET指令的样式,传到http_find_file中(这个函数默认处理GET指令),用GET指令的方法去调用CGI接口。如果用这种方法的话,还需要修改一下uri的最大长度,不然很容易超。

err_t httpd_post_receive_data(void *connection, struct pbuf *p)
{
  *(strrchr(p->payload,'&')) = 0;
  sprintf(http_uri_buf +strlen(http_uri_buf),"?%s",(char*)p->payload);
  return ERR_MEM;
}

#define LWIP_HTTPD_MAX_REQUEST_URI_LEN 256


方法二:

通过形参connection,调用extract_uri_parameters将*p中的body数据分别赋给hs的params和param_vals,因为http_find_file是针对GET指令写的,如果用这种方法的话,就要修改http_find_file函数,将http_cgi_paramcount = extract_uri_parameters(hs, params);这句话删掉,不然的话会将hs中的params和param_vals清空。

err_t httpd_post_receive_data(void *connection, struct pbuf *p)
{
  struct http_state *hs = (struct http_state *)connection;
  *(strrchr(p->payload,'&')) = 0;
  extract_uri_parameters(hs, (char*)p->payload);

  return ERR_MEM;
}


httpd_post_finished在数据接收完成后执行,由httpd_handle_post_finished调用,之后就进入http_find_file去根据uri查找对应的内容,因为header和body的内容我们在前面两个函数中已经提取出来了,这个函数就先空着。但是需要改一下httpd.c中的httpd_handle_post_finished

void httpd_post_finished(void *connection, char *response_uri, u16_t response_uri_len)
{   

}


static err_t
http_handle_post_finished(struct http_state *hs)
{
#if LWIP_HTTPD_POST_MANUAL_WND
  /* Prevent multiple calls to httpd_post_finished, since it might have already
     been called before from httpd_post_data_recved(). */
  if (hs->post_finished) {
    return ERR_OK;
  }
  hs->post_finished = 1;
#endif /* LWIP_HTTPD_POST_MANUAL_WND */
  /* application error or POST finished */
  /* NULL-terminate the buffer */
  // http_uri_buf[0] = 0;
  // httpd_post_finished(hs, http_uri_buf, LWIP_HTTPD_URI_BUF_LEN);
  return http_find_file(hs, http_uri_buf, 0);
}



这三个函数有很多种写法,可以根据你的功能逻辑进行修改,也可以参考LWIP中的post_example.c中的写法。


————————————————
版权声明:本文为CSDN博主「Rose Island」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42150654/article/details/116310982

使用特权

评论回复
沙发
biechedan| | 2023-4-15 19:47 | 只看该作者
这个GET和POST有什么不同呢?

使用特权

评论回复
板凳
xiaoyaodz| | 2023-4-15 19:55 | 只看该作者
如何实现web服务器给单片机主动发送数据

使用特权

评论回复
地板
benjaminka| | 2023-4-15 22:26 | 只看该作者
要建立一个MM32 web服务器,需要哪些软件?

使用特权

评论回复
5
lzbf| | 2023-4-16 21:48 | 只看该作者
如何测试MM32的post功能呢

使用特权

评论回复
6
nomomy| | 2023-4-16 22:04 | 只看该作者
这个使用的是什么通信方式额              

使用特权

评论回复
7
maqianqu| | 2023-4-16 22:25 | 只看该作者
MM32内部自带的网口通信的吗?

使用特权

评论回复
8
jimmhu| | 2023-4-16 23:06 | 只看该作者
这个数据交互的功能设计的不错。              

使用特权

评论回复
9
youtome| | 2023-4-18 10:47 | 只看该作者
MM32单片机通过wifi模块ESP8266连接外网web网页

使用特权

评论回复
10
primojones| | 2023-4-18 10:59 | 只看该作者
如何设置Web服务器               

使用特权

评论回复
11
bestwell| | 2023-4-18 12:19 | 只看该作者
Web服务器比较高端了。              

使用特权

评论回复
12
loutin| | 2023-4-18 14:16 | 只看该作者
POST指令访问用的是AT指令吗

使用特权

评论回复
13
tifmill| | 2023-4-18 14:36 | 只看该作者
想在MM32上做一个web服务器,远程电脑可以从网页登陆

使用特权

评论回复
14
mnynt121| | 2023-4-18 16:00 | 只看该作者
如何在Ubuntu上搭建和单片机进行数据交互的服务器

使用特权

评论回复
15
robincotton| | 2023-4-18 16:50 | 只看该作者
单片机的嵌入式网页是基于什么语言的?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

80

主题

3862

帖子

1

粉丝