我正在尝试创建一个简单的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页面上找到更多的例子,这些例子可能会帮助你完成你想要做的事情。