Muestre el resultado en la página web tan pronto como los datos estén disponibles en el servidor

Estoy escribiendo una página cgi en Python. Digamos que un cliente envía una solicitud a mi página cgi. Mi página cgi realiza el cálculo y tan pronto como tiene la primera salida, envía esa salida al cliente, pero CONTINUARÁ para hacer el cálculo y enviar otras respuestas DESPUÉS de que se envíe la primera respuesta.

¿Es posible lo que he presentado aquí? Hago esta pregunta porque, en mi conocimiento limitado, en una página cgi, las respuestas se devuelven una vez básica, una vez que se envía una respuesta, cgi-page deja de ejecutarse. Esto se hace en el lado del servidor o del lado del cliente, y ¿cómo lo implemento?

Mi servidor está ejecutando Apache. Muchas gracias.

He intentado un código de cliente de “dbr” en este foro (gracias a él me dieron la idea de cómo funciona el sondeo largo).

  BargePoller   body{ background:#000;color:#fff;font-size:.9em; } .msg{ background:#aaa;padding:.2em; border-bottom:1px #000 solid} .old{ background-color:#246499;} .new{ background-color:#3B9957;} .error{ background-color:#992E36;}   function addmsg(type, msg){ /* Simple helper to add a div. type is the name of a CSS class (old/new/error). msg is the contents of the div */ $("#messages").append( "
"+ msg +"
" ); } function waitForMsg(){ /* This requests the url "msgsrv.php" When it complete (or errors)*/ $.ajax({ type: "GET", url: "msgsrv.php", async: true, /* If set to non-async, browser shows page as "Loading.."*/ cache: false, timeout:50000, /* Timeout in ms */ success: function(data){ /* called when request to barge.php completes */ addmsg("new", data); /* Add response to a .msg div (with the "new" class)*/ setTimeout( 'waitForMsg()', /* Request next message */ 1000 /* ..after 1 seconds */ ); }, error: function(XMLHttpRequest, textStatus, errorThrown){ addmsg("error", textStatus + " (" + errorThrown + ")"); setTimeout( 'waitForMsg()', /* Try again after.. */ "15000"); /* milliseconds (15seconds) */ }, }); }; $(document).ready(function(){ waitForMsg(); /* Start the inital request */ });
BargePoll message requester!

Y aquí está mi código de servidor:

 import sys if __name__ == "__main__": sys.stdout.write("Content-Type: text/html\r\n\r\n") print "" for i in range(10): print "
%s
" % i sys.stdout.flush() print ""

Estoy esperando que la página de mi cliente muestre 1 número a la vez (0,1,2, …), pero los datos siempre salen todos a la vez (01234 …). Por favor, ayúdame a resolverlo. Muchísimas gracias chicos.

Solo un poco fuera de lugar, estoy tratando de usar el complemento jquery comet, pero no pude encontrar suficiente documentación. Las ayudas serían muy apreciadas. Gracias de nuevo: D

[edit] Ok, chicos, finalmente gracias a vuestros guías, he logrado hacer que funcione. Tienes razón cuando predices que mod_deflate es la fuente de todo esto.

En resumen, lo que he hecho aquí:

  • Para el cliente, haga una página de encuesta larga como el código html anterior

  • Para el servidor, deshabilite el mod_deflate editando el archivo /etc/apache2/mods-available/deflate.conf, comente la línea con la parte text / html y reinicie el servidor. Para asegurarse de que Python no almacena en búfer la salida, incluya #! / Usr / bin / python -u al principio de la página. Recuerde usar sys.stdout.flush () después de cada impresión que desee que aparezca en el cliente. El efecto puede no ser transparente, debe incluir time.sleep (1) para probar. :RE

Muchísimas gracias a ustedes por apoyar y ayudar a resolver esto: D

Por supuesto.

Existe un enfoque tradicional basado en el servidor, en el que el script se ejecuta solo una vez, pero tarda mucho tiempo en completarse, escupiendo fragmentos de página a medida que avanza:

 import sys, time sys.stdout.write('Content-Type: text/html;charset=utf-8\r\n\r\n') print '' for i in range(10): print '
%i
'%i sys.stdout.flush() time.sleep(1)

Al escribir una aplicación en WSGI, esto se hace haciendo que la aplicación devuelva un iterable que produzca cada bloque que desea enviar por separado, uno a la vez. Realmente recomiendo escribir a WSGI; puede implementarlo a través de CGI ahora, pero en el futuro, cuando su aplicación necesite un mejor rendimiento, puede implementarla a través de un servidor / interfaz más rápido sin tener que volver a escribir.

Ejemplo de WSGI sobre CGI:

 import time, wsgiref.handlers class MyApplication(object): def __call__(self, environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')]) return self.page() def page(self): yield '' for i in range(10): yield '
%i
'%i time.sleep(1) application= MyApplication() if __name__=='__main__': wsgiref.handlers.CGIHandler().run(application)

Tenga en cuenta que su servidor web puede frustrar este enfoque (para CGI o WSGI) al agregar un búfer propio. Esto suele suceder si está utilizando filtros de transformación de salida como mod_deflate para comprimir automáticamente la salida de la aplicación web. Tendrá que desactivar la compresión para los scripts de generación de respuesta parcial.

Esto lo limita a representar la página bit a bit a medida que ingresan nuevos datos. Puede hacerlo más bonito haciendo que el lado del cliente se encargue de modificar la página a medida que ingresan nuevos datos, por ejemplo:

 def page(self): yield ( '
-
' '' ) for i in range(10): yield ''%i time.sleep(1)

Esto se basa en las secuencias de comandos del lado del cliente, por lo que podría ser una buena idea incluir al final la copia de seguridad final no basada en secuencias de comandos.

Mientras hace esto, la página parecerá que todavía se está cargando. Si no quieres eso, entonces deberías dividir la secuencia de comandos en una primera solicitud que simplemente distribuya el contenido estático, incluida la secuencia de comandos del lado del cliente que verifica con el servidor usando uno de los XMLHttpRequest que busca nuevos datos. a través de, o, para los casos realmente prolongados, muchas solicitudes de XMLHttp, cada una de las cuales devuelve el estado y cualquier información nueva. Este enfoque es mucho más complicado, ya que significa que debe ejecutar su proceso de trabajo como un proceso de daemon en segundo plano aparte del servidor web, y pasar datos entre el daemon y la solicitud de CGI / WSGI de front-end utilizando, por ejemplo. tuberías o una base de datos.

Sí, eso es posible y no tiene mucho que hacer, ya que imprime los datos, el servidor los enviará, solo para asegurarse de seguir limpiando la salida estándar

Hay algunas técnicas.

La forma tradicional es continuar transmitiendo datos, y hacer que el navegador continúe representándolos usando una representación progresiva. Entonces, como un CGI pasado de moda, simplemente haga sys.stdout.flush() . Esto muestra una página parcial que puede seguir agregando, pero se ve torpe en el navegador porque el progtwigdor continuará girando y se parece mucho a que el servidor está colgado o sobrecargado.

Algunos navegadores admiten un multipartito multipart/x-mixed-replace que le permite hacer el mismo truco para mantener abierta la conexión, pero el navegador reemplazará la página completamente cuando envíe el siguiente fragmento de varias partes (que debe tener formato MIME) ). No sé si es utilizable: Internet Explorer no lo admite y es posible que tampoco funcione bien en otro navegador.

La siguiente forma más moderna es encuestar el servidor para obtener resultados con XMLHttpRequest de Javascript. Esto requiere que pueda verificar los resultados de la operación desde un subproceso o proceso de servidor web diferente, lo que puede ser un poco más difícil de lograr en el código del lado del servidor. Sin embargo, te permite crear una página web mucho más agradable.

Si quieres complicarte aún más, revisa el modelo “Comet” o “Web Sockets”.

El truco de los antiguos progtwigs CGI es usar el encabezado HTTP de Transfer-Encoding: chunked :

3.6.1 Codificación de transferencia fragmentada

La encoding fragmentada modifica el cuerpo de un mensaje para transferirlo como una serie de fragmentos, cada uno con su propio indicador de tamaño, seguido de un remolque OPCIONAL que contiene campos de encabezado de entidad. Esto permite que el contenido producido dinámicamente se transfiera junto con la información necesaria para que el destinatario verifique que ha recibido el mensaje completo.

Cuando haya un resultado disponible, envíelo como un fragmento separado: el navegador mostrará este mensaje HTTP independiente. Cuando otro trozo llega más tarde, se muestra una NUEVA PÁGINA .

Tendrá que producir los encabezados correctos para cada fragmento dentro del progtwig CGI . Además, recuerde que debe vaciar la salida CGI al final de cada fragmento. En Python esto se hace con sys.stdout .flush()