是否可以将gzip压缩与服务器发送事件(SSE)一起使用?

时间:2014-05-20 20:11:38

标签: python html5 gzip bottle server-sent-events

我想知道是否可以启用gzip压缩 对于服务器发送的事件(SSE;内容类型:文本/事件流)。

根据这本书,似乎有可能: http://chimera.labs.oreilly.com/books/1230000000545/ch16.html

但是我无法通过gzip压缩找到任何SSE的例子。我试过了 使用响应头字段发送gzipped消息 内容编码设置为" gzip"没有成功。

为了试验SSE,我正在测试一个小型的Web应用程序 使用瓶子框架+ gevent在Python中制作;我正在跑步 瓶子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: %s\n\n" % data)
        #yield "data: %s\n\n" % data

没有压缩的代码(最后一行,注释)并且没有gzip content-encoding标题字段就像魅力一样。

编辑:感谢回复和其他问题:Python: Creating a streaming gzip'd file-like?,我设法解决了问题:

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

2 个答案:

答案 0 :(得分:4)

TL; DR:如果请求未被缓存,您可能希望使用zlib并声明Content-Encoding为' deflate'。只有这一改变才能使你的代码有效。


如果您将Content-Encoding声明为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()

但是,如果你使用实际文件作为缓存,这才有意义。

答案 1 :(得分:2)

您还可以使用中间件,因此您不必担心为每种方法添加响应。这是我最近使用的一个。

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

这就是我使用它的方式(我使用了both.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')

对于此特定库,您可以通过修改DEFAULT_COMPRESSABLES variable来设置要压缩的w / c类型的响应

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

所有响应都通过中间件进行gzip压缩而不修改现有代码。默认情况下,它压缩内容类型属于DEFAULT_COMPRESSABLES且内容长度大于200个字符的响应。