ESP8266 MicroPython服务器如何获取POST请求体及表单参数
问题描述
我正在开发一个简单的MicroPython项目:微控制器上电后,若无法连接WiFi,将启动Access Point模式。用户连接该AP后,设备会提供一个简单网页,允许用户输入SSID和密码,这些信息将存储到设备中供后续使用。但我遇到了一个问题:无法获取用户在网页表单提交后输入的值。
原核心问题代码片段:
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
解决方案
要实现识别请求页面、读取表单参数并保存,需要对enableAccessPoint方法进行修改,核心是解析HTTP请求的方法和内容,处理POST请求的表单数据。
修改后的完整enableAccessPoint方法
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).decode('utf-8') # 解码为字符串便于解析 print('Content = %s' % request) # 解析请求方法和路径 method = request.split(' ')[0] path = request.split(' ')[1] if method == 'POST' and path == '/submit': # 提取POST请求体中的表单数据 form_data = request.split('\r\n\r\n')[-1] params = {} for pair in form_data.split('&'): key, value = pair.split('=') params[key] = value.replace('+', ' ') # 处理URL编码的空格 # 获取用户输入的SSID和密码 new_ssid = params.get('SSID', '') new_password = params.get('PASSWORD', '') # 保存新配置到config.json if new_ssid: with open('config.json', 'w') as fp: json.dump({ "ssid": new_ssid, "password": new_password, "access_point_ssid": self.access_point_ssid }, fp) # 返回配置成功页面 response = """HTTP/1.1 200 OK Content-Type: text/html <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h1>配置成功!</h1> <p>设备将重启并尝试连接新WiFi。</p> </body> </html> """ else: # 返回SSID为空的错误页面 response = """HTTP/1.1 400 Bad Request Content-Type: text/html <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h1>错误:SSID不能为空</h1> <a href="/">返回配置页面</a> </body> </html> """ else: # GET请求或其他路径,返回配置表单页面 response = """HTTP/1.1 200 OK Content-Type: text/html """ + self.getWebPage() # 发送响应给客户端 conn.send(response.encode('utf-8')) conn.close() # 配置成功后自动重启设备(可选) if method == 'POST' and path == '/submit' and new_ssid: time.sleep(2) import machine machine.reset() except KeyboardInterrupt: print("break") break except Exception as e: print('Error:', e) conn.close()
关键修改点说明
- 请求解码:将
recv获取的字节数据转为UTF-8字符串,方便后续解析。 - 请求路由:通过拆分请求头,区分GET(返回表单)和POST到
/submit(处理表单)的请求。 - 表单数据解析:POST请求的表单数据位于请求体(
\r\n\r\n分隔符之后),拆分后转为键值对,同时处理URL编码的空格。 - 配置保存:将新的SSID和密码写入
config.json,覆盖原有配置。 - 响应规范:所有响应都添加HTTP状态码和
Content-Type头,确保浏览器正确解析页面。 - 可选重启:配置完成后自动重启设备,使其立即尝试连接新WiFi。
内容的提问来源于stack exchange,提问作者Tyler Edwards
相关产品推荐
相关产品推荐

