如何在ESP8266微ython服务器中获取POST正文



我正在尝试创建一个简单的Microython项目,当微控制器第一次打开时,如果连接到wifi不成功,它将开始托管接入点。当连接到接入点时,该设备提供一个简单的网页,允许用户输入他们的SSID和密码短语,然后将其存储到设备中以供将来使用。

然而,我在表单提交后检索用户在网页中键入的值时遇到了问题。这是我的代码:

import ujson as json
import usocket as socket
import network
import time
max_wifi_retry = 30
class ConnectWifi:
# Constructor retrieves stored credentials and saves them to class variables
def __init__(self, credentialsFile='config.json'):
with open(credentialsFile) as fp:
config = json.load(fp)
self.ssid = config["ssid"]
self.password = config["password"]
self.access_point_ssid = config["access_point_ssid"]

# This method will attempt to connect device to wifi
def connectWifi(self):
self.wifi = network.WLAN(network.STA_IF)

#Restarting WiFi
self.wifi.active(False)
time.sleep(0.5)
self.wifi.active(True)

self.wifi.connect(self.ssid, self.password)

if not self.wifi.isconnected():
print('connecting')
wifi_retry_attempts = 0
while not self.wifi.isconnected() and wifi_retry_attempts < max_wifi_retry:
print(max_wifi_retry - wifi_retry_attempts)
wifi_retry_attempts += 1
time.sleep_ms(1000)

if not self.wifi.isconnected():
self.wifi.active(False)

return self.wifi.isconnected()

# This is where I am having trouble knowing what to do
def enableAccessPoint(self):
print('Unable to connect to wifi, enabling wireless access point config')
ap = network.WLAN(network.AP_IF)
ap.active(True)
ap.config(essid=self.access_point_ssid, authmode=network.AUTH_OPEN)

print(ap.ifconfig())

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)
while True:
try:
conn, addr = s.accept()
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
print('Content = %s' % str(request))
response = self.getWebPage()
conn.send(response)
conn.close()
except KeyboardInterrupt:
print("break")
break

def getWebPage(self):
html = """
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Configure Wifi</h1>
<form action="/submit" method="post">
<label for="ssid">SSID:</label><br>
<input name="SSID" type="text" id="ssid" value=""><br><br>
<label for="password">Password:</label><br>
<input name="PASSWORD" type="text" id="password" value=""><br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
"""
return html


简而言之,为了快速解释这个问题,我有一个创建并侦听请求的套接字:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)
while True:
try:
conn, addr = s.accept()
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
print('Content = %s' % str(request))
response = self.getWebPage()
conn.send(response)
conn.close()
except KeyboardInterrupt:
print("break")
break

我正试图弄清楚如何修改上面的代码,以识别用户请求的页面,并在用户提交表单时读取任何表单参数,这可能吗?

这是HTML表单以供参考。

<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Configure Wifi</h1>
<form action="/submit" method="post">
<label for="ssid">SSID:</label><br>
<input name="SSID" type="text" id="ssid" value=""><br><br>
<label for="password">Password:</label><br>
<input name="PASSWORD" type="text" id="password" value=""><br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>

一旦缓冲区中有了客户端请求,就需要对其进行解析,以找到您要查找的各个部分。有一些模块(比如GitHub上的microdot(可以用MicroPython为您完成这项工作。或者你可以自己滚。

如果你选择自己做,它会看起来像这样:

def parse_query_string(query_string):
query = {}
query_params = query_string.split('&')
for param in query_params:
if (not '=' in param):  # A key with no value, like: 'red' instead of 'color=red'
key=param
query[key] = ''
else:
key, value = param.split('=')
query[key] = value

return query

def parse_http_request(req_buffer):
assert (req_buffer != b''), 'Empty request buffer.'
req = {}
req_buffer_lines = req_buffer.decode('utf8').split('rn')
req['method'], target, req['http_version'] = req_buffer_lines[0].split(' ', 2)  # Example: GET /route/path HTTP/1.1
if (not '?' in target):
req['path'] = target
else:  # target can have a query component, so /route/path could be something like /route/path?state=on&timeout=30
req['path'], query_string = target.split('?', 1)
req['query'] = parse_query_string(query_string)
req['headers'] = {}
for i in range(1, len(req_buffer_lines) - 1):
if (req_buffer_lines[i] == ''):  # Blank line signifies the end of headers.
break
else:
name, value = req_buffer_lines[i].split(':', 1)
req['headers'][name.strip()] = value.strip()

req['body'] = req_buffer_lines[len(req_buffer_lines) - 1]  # Last line is the body (or blank if no body.)

return req

如果你把你在request中捕获的缓冲区传给parse_http_request(),如下所示:

req = parse_http_request(request)

您将得到一个名为req的字典,其中包含您需要的标题、正文等内容。

当您从网页发布表单数据时,查询字符串最终会出现在正文中。您可以使用parse_query_string()函数来获取发送的参数的python字典。如果您将表单方法设置为GET,您将在`req['query']中找到作为字典的参数。

Mozilla的开发人员网络有一个HTTP事务处理过程中发生的事情的例子。https://developer.mozilla.org/en-US/docs/Web/HTTP/Session

上面的函数是从一个名为Thimble的模块中提取的,我正在该模块上运行ESP设备上的API。你可以在项目的GitHub页面上找到更多的例子,这些例子可能会帮助你完成你想要做的事情。

最新更新