Кто-нибудь знает, почему тело ответа будет пустым в форме HTTP Post из IOS. Работает в Android - PullRequest
0 голосов
/ 13 июля 2020

Привет, мы пытаемся использовать этот WIFI Manager (https://github.com/tayfunulu/WiFiManager/blob/master/wifimgr.py) для подключения устройства ESP 32 к локальному Wi-Fi.

WIFI Manager в основном идентифицирует все SSID в local area, запускает веб-сервер на 192.168.4.1, отображает различные сети и позволяет пользователю выбрать ту, к которой он хочет подключиться. Этот процесс выполняется в мобильных браузерах (телефоны Android или IOS и любой браузер).

Это отлично работает в Android, но IOS возвращает пустое тело ответа POST. Я использовал IOS Charles и могу видеть тело ответа с правильной информацией, но оно не возвращается на сервер.

Изображение показывает заголовок ответа

Изображение 2 показывает тело ответа

Это то, что сервер получил в Andriod (данные выделены жирным шрифтом в конце потока):

клиент, подключенный из ('192.168.4.3', 47754 ) Запрос: b'POST / configure HTTP / 1.1 \ r \ nHost: 192.168.4.1 \ r \ nConnection: keep-alive \ r \ nContent-Length: 39 \ r \ nCache-Control: max-age = 0 \ r \ nUpgrade-Insecure-Requests: 1 \ r \ nOrigin: http://192.168.4.1 \ r \ nContent-Type: application / x- www-form-urlencoded \ r \ nUser-Agent: Mozilla / 5.0 (Linux; Android 7.0) AppleWebKit / 537.36 (K HTML, как Gecko) Версия / 4.0 Chrome / 83.0.4103.106 Mobile DuckDuckGo / 5 Safari / 537.36 \ r \ n Принять: text / html, application / xhtml + xml, application / xml; q = 0.9 , image / webp, image / apng, / ; q = 0.8, приложение / подписанный обмен; v = b3; q = 0.9 \ r \ nX-Requested-With: com.duckduck go. mobile.android \ r \ nReferer: http://192.168.4.1/ \ r \ nAccept-Encodi ng : gzip, deflate \ r \ nAccept-Language: en-US, en; q = 0.9 \ r \ n \ r \ n ssid = mywifi & password = abcdef1234 '

Это то, что сервер получил в IOS (нет данных в конце потока):

клиент, подключенный от ('192.168.4.2', 64482). Запрос: b'POST / configure HTTP / 1.1 \ r \ nHost: 192.168.4.1 \ r \ nПроисхождение: http://192.168.4.1 \ r \ nContent-Type: application / x- www-form-urlencoded \ r \ nAccept-Encoding: gzip, deflate \ r \ nConnection: keep-alive \ r \ nUpgrade -Insecure-Requests: 1 \ r \ nAccept: text / html, application / xhtml + xml, application / xml; q = 0.9, / ; q = 0.8 \ r \ n Пользователь-агент: Mozilla / 5.0 (iPhone; CPU iPhone OS 13_5_1 как Ma c OS X) AppleWebKit / 605.1.15 (K HTML, как Gecko) Mobile / 15E148 DuckDuckGo / 7 \ r \ nReferer: http://192.168.4.1/ \ r \ nContent- Длина : 39 \ r \ nAccept-Language: en-us \ r \ n \ r \ n '

Я понимаю, что заголовок ответа Charles и данные отличаются от приведенного выше абзаца IOS, но тот же результат. Я пробовал Safari, Chrome и FF на iphone с теми же результатами. Я убедился, что в настройках конфиденциальности разрешены сторонние данные, но, возможно, есть еще одно место, которое я пропустил. Приведен приведенный ниже код действия формы (def handle_ root (client), который открывает экран для отображения всех локальных сетей Wi-Fi и ниже, что запускается веб-сервер (Def start (port = 80)).

Спасибо, Джим.

Форма для выбора пользователем SSID для подключения:

def send_header(client, status_code=200, content_length=None ):
    client.sendall("HTTP/1.0 {} OK\r\n".format(status_code))
    client.sendall("Content-Type: text/html\r\n")
    if content_length is not None:
       client.sendall("Content-Length: {}\r\n".format(content_length))
    client.sendall("\r\n")

def handle_root(client):
wlan_sta.active(True)
ssids = sorted(ssid.decode('utf-8') for ssid, *_ in wlan_sta.scan())
send_header(client)
client.sendall("""\
    <html>
        <h1 style="color: #5e9ca0; text-align: center;">
            <span style="color: #ff0000;">
                Wi-Fi Client Setup
            </span>
        </h1>
        <form action="configure" method="post">
            <table style="margin-left: auto; margin-right: auto;">
                <tbody>
""")
while len(ssids):
    ssid = ssids.pop(0)
    client.sendall("""\
                    <tr>
                        <td colspan="2">
                            <input type="radio" name="ssid" value="{0}" />{0}
                        </td>
                    </tr>
    """.format(ssid))
client.sendall("""\
                    <tr>
                        <td>Password:</td>
                        <td><input name="password" type="password" /></td>
                    </tr>
                </tbody>
            </table>
            <p style="text-align: center;">
                <input type="submit" value="Submit" />
            </p>
        </form>
        <p>&nbsp;</p>
        <hr />
        <h5>
            <span style="color: #ff0000;">
                Your ssid and password information will be saved into the
                "%(filename)s" file in your ESP module for future usage.
                Be careful about security!
            </span>
        </h5>
        <hr />
        <h2 style="color: #2e6c80;">
            Some useful infos:
        </h2>
        <ul>
            <li>
                Original code from <a href="https://github.com/cpopp/MicroPythonSamples"
                    target="_blank" rel="noopener">cpopp/MicroPythonSamples</a>.
            </li>
            <li>
                This code available at <a href="https://github.com/tayfunulu/WiFiManager"
                    target="_blank" rel="noopener">tayfunulu/WiFiManager</a>.
            </li>
        </ul>
    </html>
""" % dict(filename=NETWORK_PROFILES))
client.close()

def start(port=80):
global server_socket

addr = socket.getaddrinfo('0.0.0.0', port)[0][-1]

stop()

wlan_sta.active(True)
wlan_ap.active(True)

wlan_ap.config(essid=ap_ssid, password=ap_password, authmode=ap_authmode)

server_socket = socket.socket()
server_socket.bind(addr)
server_socket.listen(1)

print('Connect to WiFi ssid ' + ap_ssid + ', default password: ' + ap_password)
print('and access the ESP via your favorite web browser at 192.168.4.1.')
print('Listening on:', addr)

while True:
    if wlan_sta.isconnected():
        return True

    client, addr = server_socket.accept()
    print('client connected from', addr)
    try:
        client.settimeout(5.0)

        request = b""
        try:
            while "\r\n\r\n" not in request:
                request += client.recv(512)
        except OSError:
            pass

        print("Request is: {}".format(request))
        if "HTTP" not in request:  # skip invalid requests
            continue

        # version 1.9 compatibility
        try:
            url = ure.search("(?:GET|POST) /(.*?)(?:\\?.*?)? HTTP", request).group(1).decode("utf-8").rstrip("/")
        except Exception:
            url = ure.search("(?:GET|POST) /(.*?)(?:\\?.*?)? HTTP", request).group(1).rstrip("/")
        print("URL is {}".format(url))

        if url == "":
            handle_root(client)
        elif url == "configure":
            handle_configure(client, request)
        else:
            handle_not_found(client, url)

    finally:
        client.close()

Рабочий процесс WIFI Manager

1 Ответ

0 голосов
/ 31 июля 2020

Наконец-то разобрался. Так получается, и, возможно, это очевидно для тех, кто знаком с протоколом сокетов HTTP, но в мобильной ОС Android тело ответа возвращается с заголовком в конце, а при IOS вам нужно выполнить еще один «recv», чтобы получить тело ответа. надеюсь, что это поможет кому-то и сэкономит им недели копаний и тревог.

...