Можно ли использовать сжатие gzip с событиями, отправленными сервером (SSE)?

Я хотел бы знать, можно ли включить сжатие gzip для событий, отправленных сервером (SSE ; Content-Type: text/event-stream).

Кажется, это возможно, согласно этой книге: http://chimera.labs.oreilly.com/books/1230000000545/ch16.html

но я не могу найти ни одного примера SSE с сжатием gzip. Я пытался отправка сообщений gzipped с полем заголовка ответа Контент-Кодирования установить в "gzip" без успех.

для экспериментов вокруг SSE я тестирую небольшое веб-приложение сделано в Python с бутылкой framework + gevent ; я просто бегу бутылка WSGI сервер:

@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: %snn" % data)
        #yield "data: %snn" % data

код без сжатия (последняя строка, комментарий) и без gzip поле заголовка content-encoding работает как шарм.

редактировать: спасибо за ответ и на другой вопрос: Python: создание потокового файла gzip'D?, мне удалось чтобы решить проблему:

@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: %snn" % data)
        yield compressed_stream.flush(zlib.Z_SYNC_FLUSH)

2 ответов


TL; DR: Если запросы не кэшируются, вы, вероятно, захотите использовать zlib и объявить кодировку содержимого "deflate". Одно это изменение должно заставить ваш код работать.


Если вы объявляете кодировку содержимого gzip, вам нужно фактически использовать gzip. Они основаны на том же алгоритме сжатия, но gzip имеет дополнительное кадрирование. Это работает, например:

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

это действительно имеет смысл, только если вы используете фактический файл в качестве кэша.


есть также промежуточное ПО, которое вы можете использовать, поэтому вам не нужно беспокоиться о gzipping ответах для каждого из ваших методов. Вот я недавно пользовался.

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

вот как я его использовал (я использую bottle.py с сервером gevent)

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

для этой конкретной библиотеки вы можете установить типы ответов w/c, которые вы хотите сжать, изменив DEFAULT_COMPRESSABLES variable для пример

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'])

все ответы проходят через промежуточное ПО и получают gzipped без изменения существующего кода. По умолчанию он сжимает ответы, тип содержимого которых принадлежит DEFAULT_COMPRESSABLES и длина содержимого которого превышает 200 символов.