unrecognized run not found emperor app python http client-server uwsgi wsgi

python - run - Enviar el estado intermitente de la solicitud antes de enviar la respuesta real



uwsgi flask (3)

Tengo un servidor, que tarda unos minutos en procesar una solicitud específica y luego responde a ella.

El cliente debe esperar la respuesta sin saber cuándo se completará.

¿Hay alguna manera de informar al cliente sobre el estado del procesamiento? (por ejemplo, 50% completado, 80% completado), sin que el cliente tenga que sondear el estado.


Esta respuesta probablemente no sea de ayuda en su caso particular, pero puede serle de ayuda en otros casos.

El protocolo HTTP admite respuestas informativas (1xx) :

indica una respuesta provisional para comunicar el estado de la conexión o el progreso de la solicitud antes de completar la acción solicitada y enviar una respuesta final

Incluso hay un código de estado precisamente para su caso de uso, 102 (Procesamiento) :

respuesta provisional utilizada para informar al cliente de que el servidor ha aceptado la solicitud completa, pero aún no la ha completado

El código de estado 102 se eliminó de las ediciones posteriores de ese estándar debido a la falta de implementaciones, pero aún está registered y podría usarse.

Por lo tanto, podría verse así (HTTP / 2 tiene una forma binaria equivalente):

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!

Desafortunadamente, esto no es ampliamente soportado. En particular, WSGI no proporciona una manera de enviar respuestas 1xx arbitrarias. Los clientes admiten las respuestas 1xx en el sentido de que deben analizarlas y tolerarlas , pero generalmente no les dan acceso programático: en este ejemplo, el encabezado Progress no estará disponible para la aplicación cliente.

Sin embargo, las respuestas 1xx pueden seguir siendo útiles (si el servidor puede enviarlas) porque tienen el efecto de restablecer el tiempo de espera de lectura del socket del cliente , que es uno de los principales problemas con respuestas lentas.


Sin utilizar ninguna de las técnicas más nuevas (websockets, webpush / http2, ...), anteriormente he usado una solución Pushlet simplificada o de sondeo largo para HTTP 1.1 y varios javascript o implementación de cliente propio. Si mi solución no se ajusta a su caso de uso, siempre puede buscar esos dos nombres en Google para encontrar otras formas posibles.

El cliente envía una solicitud, lee 17 bytes (respuesta http inicial) y luego lee 2 bytes a la vez para obtener el estado de procesamiento.

El servidor envía una respuesta HTTP válida y durante el progreso de la solicitud envía 2 bytes de porcentaje completado, hasta que los últimos 2 bytes están "bien" y cierra la conexión.

ACTUALIZADO: Ejemplo 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()

ACTUALIZADO: Ejemplo de solicitudes client.py

import requests response = requests.get(''http://localhost:8080/'', stream=True) for r in response.iter_content(chunk_size=2): print(r)

Servidor de ejemplo (solo usar para pruebas :)

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()

Si los últimos 2 bytes no están "bien", maneje el error de alguna otra manera. Esto no es un cumplimiento hermoso del código de estado HTTP, sino más bien una solución que funcionó para mí hace muchos años.

ejemplo de cliente 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.


Use la codificación de transferencia fragmentada , que es una técnica estándar para transmitir flujos de longitud desconocida.

Ver: Wikipedia - Codificación de transferencia fragmentada

Aquí, una implementación de servidor python disponible como una esencia en GitHub:

Envía contenido usando codificación de transferencia fragmentada usando módulos de biblioteca estándar

En el cliente, si el servidor notificó la codificación de transferencia fragmentada, solo tendría que:

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 , porque los trozos son dinámicos y estarán determinados por la información en las convenciones simples de la semántica de transferencia fragmentada.

Consulte: http://docs.python-requests.org/en/master/user/advanced/#chunk-encoded-requests

Cuando ve, por ejemplo, 100 en el contenido de la respuesta r , sabe que la siguiente parte será el contenido real después de procesar el 100 .