2014-05-20 7 views
7

Ich würde gerne wissen, ob es möglich ist, Gzip-Komprimierung für Server-Gesendete Ereignisse (SSE; Content-Type: Text/Event-Stream) zu aktivieren.Ist es möglich, Gzip-Komprimierung mit Server-Sent Events (SSE) zu verwenden?

Es scheint, es möglich ist, nach diesem Buch: http://chimera.labs.oreilly.com/books/1230000000545/ch16.html

Aber ich kann kein Beispiel von SSE mit gzip-Komprimierung nicht finden. Ich habe versucht, gziped Nachrichten mit der Antwort-Header-Feld senden Content-Encoding auf "gzip" ohne Erfolg gesetzt.

Zum Experimentieren mit SSE teste ich eine kleine Webanwendung in Python mit dem bottle framework + gevent; Ich bin gerade die Flasche WSGI-Server ausgeführt wird:

@bottle.get('/data_stream') 
def stream_data(): 
    bottle.response.content_type = "text/event-stream" 
    bottle.response.add_header("Connection", "keep-alive") 
    bottle.response.add_header("Cache-Control", "no-cache") 
    bottle.response.add_header("Content-Encoding", "gzip") 
    while True: 
     # new_data is a gevent AsyncResult object, 
     # .get() just returns a data string when new 
     # data is available 
     data = new_data.get() 
     yield zlib.compress("data: %s\n\n" % data) 
     #yield "data: %s\n\n" % data 

Der Code ohne Komprimierung (letzte Zeile, kommentiert) und ohne gzip Content-Encoding-Header-Feld wirkt wie ein Zauber.

EDIT: Dank der Antwort und auf diese andere Frage: Python: Creating a streaming gzip'd file-like? gelang es mir, das Problem zu lösen:

@bottle.route("/stream") 
def stream_data(): 
    compressed_stream = zlib.compressobj() 
    bottle.response.content_type = "text/event-stream" 
    bottle.response.add_header("Connection", "keep-alive") 
    bottle.response.add_header("Cache-Control", "no-cache, must-revalidate") 
    bottle.response.add_header("Content-Encoding", "deflate") 
    bottle.response.add_header("Transfer-Encoding", "chunked") 
    while True: 
     data = new_data.get() 
     yield compressed_stream.compress("data: %s\n\n" % data) 
     yield compressed_stream.flush(zlib.Z_SYNC_FLUSH) 

Antwort

4

TL; DR: Wenn die Anforderungen nicht im Cache gespeichert werden, möchten Sie wahrscheinlich verwenden zlib und deklarieren Sie, dass Content-Encoding "deflate" ist. Diese Änderung sollte Ihren Code funktionieren lassen.


Wenn Sie Content-Encoding als gzip deklarieren, müssen Sie gzip verwenden. Sie basieren auf dem gleichen Komprimierungsalgorithmus, aber gzip verfügt über zusätzliche Framing-Funktionen. Dies funktioniert, zum Beispiel:

import gzip 
import StringIO 
from bottle import response, route 
@route('/') 
def get_data(): 
    response.add_header("Content-Encoding", "gzip") 
    s = StringIO.StringIO() 
    with gzip.GzipFile(fileobj=s, mode='w') as f: 
     f.write('Hello World') 
    return s.getvalue() 

Die einzigen wirklich sinnvoll ist, wenn Sie eine tatsächliche Datei als Cache verwenden, though.

+0

Danke für Ihre Erklärung. In der Tat hilft das Ändern der Content-Encoding auf Deflate ein bisschen: die erste Nachricht wird auf der Client-Seite verarbeitet. Aber nur die erste :(Haben Sie eine Idee warum? Vielen Dank im Voraus – mguijarr

+0

Versuchen Sie, für jeden Datenblock unabhängig compress aufzurufen? Ich denke nicht, dass das funktioniert. Alle Daten sollten in einem einzigen komprimierten Stream sein.Das bedeutet, dass gzip mit seiner Streaming-Schnittstelle tatsächlich der richtige Weg ist. Allerdings müsste ich mehr von Ihrem Code sehen, um bestimmte Zeiger zu bieten. – otus

+0

Danke eine Million; endlich klappt es! Ich habe meine Frage bearbeitet, um zu sagen, was ich ändern musste. – mguijarr

2

Es gibt auch Middleware, die Sie verwenden können, sodass Sie sich keine Gedanken darüber machen müssen, wie Sie die Antworten für jede Ihrer Methoden abrufen können. Hier ist eine, die ich kürzlich benutzt habe.

https://code.google.com/p/ibkon-wsgi-gzip-middleware/

Dies ist, wie ich es benutzt (ich bin mit GEVENT Server mit bottle.py)

from gzip_middleware import Gzipper 
import bottle 
app = Gzipper(bottle.app()) 
run(app = app, host='0.0.0.0', port=8080, server='gevent') 

Für diese spezielle Bibliothek können Sie einstellen, w/c Arten von Antworten Sie komprimieren möchten, indem Sie die DEFAULT_COMPRESSABLES variable zum Beispiel Modifizieren

DEFAULT_COMPRESSABLES = set(['text/plain', 'text/html', 'text/css', 
'application/json', 'application/x-javascript', 'text/xml', 
'application/xml', 'application/xml+rss', 'text/javascript',  
'image/gif']) 

Alle Antworten über die Middleware gehen und ohne Änderung Ihrer bestehenden Code gzipped erhalten. Standardmäßig komprimiert es Antworten, deren Inhaltstyp zu DEFAULT_COMPRESSABLES gehört und deren Inhaltslänge größer als 200 Zeichen ist.

+0

Danke für Ihre Antwort – mguijarr

Verwandte Themen