You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 15:00:53