自学内容网 自学内容网

microPython搭建webServer--(二)使用microdot库实现对用户提交数据的响应

  1. 用户提交数据,get与post
    用户用在网页中常用的提交数据模式有两种,get和post,各有优缺点。
    get看起来比较简单,因为数据都是明文发送的,比如:
https://cn.bing.com/?q=python

在网址的后面加个?,之后q=python告诉具体的搜索参数,服务器解析出来参数后,作出相应,并将结果发送给浏览器。

除了用问号传参,还可以使用斜杠,比如:

http://192.168.4.1:5000/users/1234

在上面的地址中,users是参数名,1234是参数数值。

相对于get,post提交的数据是不显示在地址栏中的,可以用js代码对cookie或者其他变量封装成json格式,提交给服务器。

  1. 对get的响应
@app.get('/on')
def index(request):
    # 如果收到get请求on就开灯    
    return "开灯了"

如果想给esp32一个简易的指令,比如开灯,那只要定义对应命令的装饰器,比如"/on",收到on请求后,执行对应的开灯动作,操作某个gpio,并返回浏览器处理结果。

@app.get('/users/<int:id>')
def get_user(request, id):
    print("id=",id)    
    return "users={}".format(id)

如果是命令后面带参数,比如users=1234,那么,可以在地址后面加上“/命令/参数”,定义对应的装饰器,得到参数后做出对应动作。当然,这个参数也可以是字符串。
完整代码如下:


from microdot import Microdot
import network
# 创建一个WLAN对象,并将其设置为AP模式(接入点模式)
ap = network.WLAN(network.AP_IF)
ap.active(True)

# 配置接入点的参数,包括SSID(网络名称)和密码
ap.config(essid='MyESP32AP', password='password123')

# 打印接入点的IP地址
print('AP IP address:', ap.ifconfig())
app = Microdot()

html = '''<!DOCTYPE html>
<html>
    <head>        
        <meta charset="UTF-8">        
    </head>
    <body >
        <h1>地址栏中输入"ip地址/users/333"</h1>
        <h1>地址栏中输入"ip地址/on"</h1>
    </body>
</html>
'''

@app.route('/', methods=['GET', 'POST'])
async def hello(request):
    return html, 200, {'Content-Type': 'text/html'}

@app.get('/users/<int:id>')
def get_user(request, id):
    print("id=",id)    
    return "users={}".format(id)

@app.get('/on')
def index(request):
    # 如果收到get请求on就开灯    
    return "开灯了"


app.run(host='192.168.4.1',debug=True)

3. 对post的响应
先看一下,一个网页最基本的post框架应该包含什么:
基本post

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
</head>

<body>
    <form action="http://192.168.4.1:5000/post" method="post">
        ID:<input type="text" name="username" />
        Password:<input type="password" name="password" />
        <select name="fruits" id="fruits">
            <option value="apple">苹果</option>
            <option value="banana">香蕉</option>
            <option value="orange">橙子</option>
        </select>
        <input type="submit" value="Submit" />
    </form>
</body>

</html>

在html文档中,放入form元素,action属性指向接下来要把数据提交给谁,method是提交方法。form中的元素,必备的是提交按钮,点击这个按钮后,浏览器会自动遍历form中所有可以提交的数据,完成提交过程。
本例中,放置了两个文本框输和一个下拉菜单,当然也可以放置更多的元素,遍历时,会将各元素的name和所对应的值生成数组。
接下来,在webServer中定义一个装饰器,对post的内容做相应的处理即可:

from microdot import Microdot
import network
# 创建一个WLAN对象,并将其设置为AP模式(接入点模式)
ap = network.WLAN(network.AP_IF)
ap.active(True)

# 配置接入点的参数,包括SSID(网络名称)和密码
ap.config(essid='MyESP32AP', password='password123')

# 打印接入点的IP地址
print('AP IP address:', ap.ifconfig())
app = Microdot()

html = '''<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
</head>

<body>
    <form action="http://192.168.4.1:5000/post" method="post">
        ID:<input type="text" name="username" />
        Password:<input type="password" name="password" />
        <select name="fruits" id="fruits">
            <option value="apple">苹果</option>
            <option value="banana">香蕉</option>
            <option value="orange">橙子</option>
        </select>
        <input type="submit" value="Submit" />
    </form>
</body>

</html>
'''

@app.route('/', methods=['GET', 'POST'])
async def hello(request):
    return html, 200, {'Content-Type': 'text/html'}


@app.post('/post')
def hello(request):
    print("methon=",request.method)
    print("form=",request.form)
    print("json=",request.json)
    print("body=",request.body)
    return 'post ok'



app.run(host='192.168.4.1',debug=True)

定义好@app.post(‘/post’),对传过来的请求打印一下,可以看到数据:

methon= POST
form= {'fruits': ['apple'], 'password': ['456'], 'username': ['']}
json= None
body= b'username=&password=456&fruits=apple'

可以看到,浏览器提交的request,body内容为b’username=&password=456&fruits=apple’,你可以根据自己的需要分割字符串来提取各个变量,也可以直接调用request.form,这是microdot根据body解码出来的。

  1. 另一种post的方式

在post的时候,还可以用js代码来提交,比如要在提交的时候附带系统时间戳,这样就可以摆脱form元素的限制。

 var myObject = {};
            // 添加两个字符串字段,字段名字是预设的,值可以从文本框之类的获取
            myObject.name = "Tom";
            myObject.pwd = "1234";
            //动态添加字段,字段名可以用户指定的。
            var str="age";
            var vle=18;            
            myObject[str]=vle;

            // 发送POST请求
            fetch('http://192.168.4.1:5000/post', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(myObject)
            })
                .catch(error => {
                    console.error('Error:', error);
                });

在上面这段代码中,首先定义一个myObject对象,添加一些属性后,用JSON.stringify转换为字符串输出给服务器。在消息头中,要注明’Content-Type’: ‘application/json’,这样服务器才能正确解析json字符串。
完整的microPython代码:

#使用js的fetch提交表单
import gc
print('memory:', gc.mem_free() + gc.mem_alloc())
 


from microdot import Microdot
import network
# 创建一个WLAN对象,并将其设置为AP模式(接入点模式)
ap = network.WLAN(network.AP_IF)
ap.active(True)

# 配置接入点的参数,包括SSID(网络名称)和密码
ap.config(essid='MyESP32AP', password='password123')

# 打印接入点的IP地址
print('AP IP address:', ap.ifconfig())
app = Microdot()

html = '''<!DOCTYPE html>
<html>

<head>
    <script>
        function send1word() {
            var myObject = {};
            // 添加两个字符串字段,字段名字是预设的,值可以从文本框之类的获取
            myObject.name = "Tom";
            myObject.pwd = "1234";
            //动态添加字段,字段名可以用户指定的。
            var str="age";
            var vle=18;            
            myObject[str]=vle;

            // 发送POST请求
            fetch('http://192.168.4.1:5000/post', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(myObject)
            })
                .catch(error => {
                    console.error('Error:', error);
                });
        }
        function onload() {
            console.log("onload");           

        }
    </script>
</head>

<body οnlοad="onload()">
    <input type="button" οnclick="send1word()" value="send a word">
</body>

</html>
'''

@app.route('/', methods=['GET', 'POST'])
async def hello(request):
    return html, 200, {'Content-Type': 'text/html'}


@app.post('/post')
def hello(request):
    print("methon=",request.method)
    print("form=",request.form)
    print("json=",request.json)
    print("body=",request.body)
    return 'post ok'



app.run(host='192.168.4.1',debug=True)


点击网页上的按钮后,thonny打印出:

methon= POST
form= None
json= {'age': 18, 'name': 'Tom', 'pwd': '1234'}
body= b'{"name":"Tom","pwd":"1234","age":18}'

对比前后两种提交post的方式可以发现,用html的submit提交之后,服务器显示form有内容,json为空;
用js的fetch提交之后,服务器显示收到的form为空,json有内容。
归根到底,都是body的内容,被microdot解码后,存入到哪里,fetch方式之所以存入json,是因为在消息头中声明了application/json,也就是已经告诉webServer接下来发送的就是json。


原文地址:https://blog.csdn.net/weixin_43833645/article/details/145133861

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!