Отправлять прерывистый статус запроса перед отправкой фактического ответа
У меня есть сервер, который занимает несколько минут для обработки конкретного запроса, а затем отвечает на него.
Клиент должен продолжать ждать ответа, не зная, когда он будет завершен.
Есть ли способ сообщить клиенту о состоянии обработки? (скажем, 50% завершено, заполнено на 80%), без необходимости опроса клиента.
Ответы
Ответ 1
Без использования каких-либо новых методов (websockets, webpush/http2,...) я ранее использовал упрощенное решение Pushlet или Long > для HTTP 1.1 и различные javascript или собственные реализации клиента. Если мое решение не подходит в вашем случае использования, вы всегда можете указать эти два имени Google для дальнейших возможных путей.
Client
отправляет запрос, считывает 17 байтов (Инитальный HTTP-ответ), а затем считывает 2 байта за время получения статуса обработки.
Сервер
отправляет действительный ответ HTTP и во время выполнения запроса отправляет 2 байта процента, до тех пор, пока последние 2 байта не будут "ok" и не закрывают соединение.
ОБНОВЛЕНО: Пример uwsgi server.py
from time import sleep
def application(env, start_response):
start_response('200 OK', [])
def working():
yield b'00'
sleep(1)
yield b'36'
sleep(1)
yield b'ok'
return working()
ОБНОВЛЕНО: Примеры запросов client.py
import requests
response = requests.get('http://localhost:8080/', stream=True)
for r in response.iter_content(chunk_size=2):
print(r)
Пример сервера (используется только для тестирования:)
import socket
from time import sleep
HOST, PORT = '', 8888
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(1)
while True:
client_connection, client_address = listen_socket.accept()
request = client_connection.recv(1024)
client_connection.send('HTTP/1.1 200 OK\n\n')
client_connection.send('00') # 0%
sleep(2) # Your work is done here
client_connection.send('36') # 36%
sleep(2) # Your work is done here
client_connection.sendall('ok') # done
client_connection.close()
Если последние 2 байта не являются "ок", обработайте ошибку как-нибудь иначе. Это не красивое соответствие кода статуса HTTP, но более обходное решение, которое работало для меня много лет назад.
Пример клиента telnet
$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
HTTP/1.1 200 OK
0036okConnection closed by foreign host.
Ответ 2
Использовать кодировку с канальным передачей, которая является стандартной методикой для передачи потоков неизвестной длины.
Смотрите: Википедия - кодировка с кодировкой передачи
Здесь реализована реализация сервера python как сущность GitHub:
Он отправляет контент с использованием кодирования с коротким передачей с использованием стандартных библиотечных модулей
В клиенте, если серверное кодирование с канальной передачей было уведомлено сервером, вам нужно будет:
import requests
response = requests.get('http://server.fqdn:port/', stream=True)
for r in response.iter_content(chunk_size=None):
print(r)
chunk_size=None
, потому что куски являются динамическими и будут определяться информацией в простых условностях семантики передачи с номером.
Смотрите: http://docs.python-requests.org/en/master/user/advanced/#chunk-encoded-requests
Когда вы видите, например, 100
в содержании ответа r
, вы знаете, что следующий фрагмент будет фактическим содержимым после обработки 100
.
Ответ 3
Этот ответ, вероятно, не поможет в вашем конкретном случае, но он может помочь в других случаях.
Протокол HTTP поддерживает информационные (1xx) ответы:
указывает промежуточный ответ для сообщения состояния соединения или прогресса запроса до завершения запрошенного действия и отправки окончательного ответ
Существует даже код состояния для вашего варианта использования, 102 (Обработка):
промежуточный ответ, используемый для информировать клиента о том, что сервер принял полный запрос, но еще не завершил его
Код состояния 102 был удален из последующих выпусков этого стандарта из-за отсутствия реализаций, но он по-прежнему зарегистрирован и может быть использован.
Итак, это может выглядеть так (HTTP/2 имеет эквивалентную двоичную форму):
HTTP/1.1 102 Processing
Progress: 50%
HTTP/1.1 102 Processing
Progress: 80%
HTTP/1.1 200 OK
Date: Sat, 05 Aug 2017 11:53:14 GMT
Content-Type: text/plain
All done!
К сожалению, это не широко поддерживается. В частности, WSGI не предоставляет способ отправки произвольных ответов 1xx. Клиенты поддерживают ответы 1xx в том смысле, что они необходимы для синтаксического анализа и терпимости к ним, но обычно они не предоставляют программный доступ к ним: в этом примере заголовок Progress
не будет доступен клиенту приложение.
Тем не менее, ответы 1xx могут по-прежнему быть полезными (если сервер может их отправить), поскольку они имеют эффект сброса тайм-аута чтения сокета клиентов, что является одной из основных проблем с медленными ответами.