2014-05-20 3 views
7

나는 서버 전송 이벤트 (; 텍스트/이벤트 스트림 콘텐츠 형식 SSE)에 대한 gzip 압축 을 가능하게 할 수 있는지 알고 싶습니다. http://chimera.labs.oreilly.com/books/1230000000545/ch16.htmlSSE (Server-Sent Events)에서 gzip 압축을 사용할 수 있습니까?

하지만 gzip 압축과 SSE의 예를 찾을 수 없습니다 :

이 책에 따르면,이 가능 보인다. 나는 응답 헤더 필드 콘텐츠 인코딩 세트 성공없이 "gzip을"에와 gzip으로 압축 된 메시지를 보낼 로했습니다. SSE 주위 실험에 대한

, 나는 병 프레임 워크 + 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: %s\n\n" % data) 
     #yield "data: %s\n\n" % data 

코드를 (마지막 줄 주석)와 gzip없이 컨텐츠 인코딩 헤더 필드 마법처럼 작동합니다.

편집 : 응답에이 다른 질문에 대한 감사 : 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) 

답변

4

TL; DR : 요청이 캐시되지 않은 경우, 당신은 가능성이 사용하고자하는 zlib을 사용하고 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() 

실제 파일을 캐시로 사용하는 경우에만 효과가 있습니다.

+0

감사합니다. 사실, 압축을 풀기 위해 Content-Encoding을 변경하면 약간의 도움이됩니다. 첫 번째 메시지는 클라이언트 측에서 처리됩니다. 그러나 첫 번째 :(이유는 무엇입니까?) 미리 감사드립니다. – mguijarr

+0

각 데이터 블록에 대해 독립적으로 compress를 호출하려고합니까? 작동하지 않을 것입니다. 모든 데이터는 단일 압축 스트림에 있어야합니다.즉, 스트리밍 인터페이스가있는 gzip이 실제로 이동하는 방법 일 수 있습니다. 그러나 특정 포인터를 제공하기 위해 더 많은 코드를 볼 필요가 있습니다. – otus

+0

감사합니다. 마침내 그것은 작동한다! 나는 내 질문을 편집하여 내가 무엇을 바꾸어야하는지 알렸다. – mguijarr

2

가이기도 그렇게 당신이 각각의 방법에 대한 대응을 Gzip으로 압축에 대해 걱정할 필요가 없습니다 사용할 수 있습니다 미들웨어. 최근에 제가 사용한 책이 하나 있습니다. 당신은 설정할 수 있습니다,이 특정 라이브러리의

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

(필자는 gevent 서버와 bottle.py 사용하고 있습니다)를 사용하는 방법

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

이다 w/응답의 종류 다 당신 예를

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 variable을 수정하여 압축 할. 기본적으로 콘텐츠 유형이 DEFAULT_COMPRESSABLES이고 응답 길이가 200자를 초과하는 응답을 압축합니다. 당신의 설명은

+0

답변 해 주셔서 감사합니다. – mguijarr