2017-11-11 16 views
0

나는 HTTP/JSON Bottle Web 프레임 워크 덕분에 Python으로 구현 된 안정된 서버를 가졌다. 나는 클라이언트에 보내진 데이터를 Gzip하고 싶다. (내가 --compressed 옵션 태그를 사용하는 경우) Httpie가 내 Bottle API를 디코딩 할 수 없음 Gzipped

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
# 
# curl -H "Content-Type: application/json" -X POST -d '{"key1": 1, "key2": 2}' http://localhost:6789/post 
# 

from bottle import run, request, post, route, response 
from zlib import compress 
import json 

data = {'my': 'json'} 


@post('/post') 
def api_post(): 
    global data 
    data = json.loads(request.body.read()) 
    return(data) 


@route('/get') 
def api_get(): 
    global data 
    response.headers['Content-Encoding'] = 'identity' 
    return(json.dumps(data).encode('utf-8')) 


@route('/getgzip') 
def api_get_gzip(): 
    global data 
    if 'gzip' in request.headers.get('Accept-Encoding', ''): 
     response.headers['Content-Encoding'] = 'gzip' 
     ret = compress(json.dumps(data).encode('utf-8')) 
    else: 
     response.headers['Content-Encoding'] = 'identity' 
     ret = json.dumps(data).encode('utf-8') 
    return(ret) 


run(host='localhost', port=6789, debug=True) 

내가 컬 내 서버를 테스트

는, 결과는 좋다 : HTTPie (또는 파이어 폭스 나 크롬

$ curl -H "Accept-encoding: gzip, deflated" -v --compressed http://localhost:6789/getgzip 
* Trying 127.0.0.1... 
* Connected to localhost (127.0.0.1) port 6789 (#0) 
> GET /getgzip HTTP/1.1 
> Host: localhost:6789 
> User-Agent: curl/7.47.0 
> Accept: */* 
> Accept-encoding: gzip, deflated 
> 
* HTTP 1.0, assume close after body 
< HTTP/1.0 200 OK 
< Date: Sun, 12 Nov 2017 09:09:09 GMT 
< Server: WSGIServer/0.1 Python/2.7.12 
< Content-Length: 22 
< Content-Encoding: gzip 
< Content-Type: text/html; charset=UTF-8 
< 
* Closing connection 0 
{"my": "json"} 

하지만 .. .) :

$ http http://localhost:6789/getgzipHTTP/1.0 200 OK 
Content-Encoding: gzip 
Content-Length: 22 
Content-Type: text/html; charset=UTF-8 
Date: Sun, 12 Nov 2017 09:10:10 GMT 
Server: WSGIServer/0.1 Python/2.7.12 

http: error: ContentDecodingError: ('Received response with content-encoding: gzip, but failed to decode it.', error('Error -3 while decompressing: incorrect header check',)) 

어떤 생각? Httpie의 문서에 따르면

답변

1

I Nicolargo,

는 기본 인코딩은 Accept-Encoding: gzip, deflate로 설정되어 있지만 당신은 Lempel–Ziv–Welch Compression Algorithm (Gzip으로는 DEFLATE Algorithm을 기반으로) 구현 zlib 모듈의 compress 파이썬 기능을 사용하고 있습니다.

또는 Bottle (https://bottlepy.org/docs/dev/recipes.html#gzip-compression-in-bottle)의 설명서에 따르면 gzip 압축을 수행하기 위해 사용자 정의 미들웨어가 필요합니다 (예제는 http://svn.cherrypy.org/tags/cherrypy-2.1.1/cherrypy/lib/filter/gzipfilter.py 참조).

편집 :

zlibcompress 모듈의 기능은 호환 GZIP 압축을 수행 할.

데이터의 header과 더 관련 있다고 생각합니다 (오류 언급). http://svn.cherrypy.org/tags/cherrypy-2.1.1/cherrypy/lib/filter/gzipfilter.py에는 write_gzip_header을 사용할 수도 있습니다.

0

Guillaume의 편집 섹션 덕분에 이제는 Httpie와 Curl 모두에서 작동합니다. ...

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
# 
# curl -H "Content-Type: application/json" -X POST -d '{"key1": 1, "key2": 2}' http://localhost:6789/post 
# 

from bottle import run, request, post, route, response 
import zlib 
import json 
import struct 
import time 

data = {'my': 'json'} 


@post('/post') 
def api_post(): 
    global data 
    data = json.loads(request.body.read()) 
    return(data) 


@route('/get') 
def api_get(): 
    global data 
    response.headers['Content-Encoding'] = 'identity' 
    return(json.dumps(data).encode('utf-8')) 


@route('/getgzip') 
def api_get_gzip(): 
    global data 
    ret = json.dumps(data).encode('utf-8') 
    if 'gzip' in request.headers.get('Accept-Encoding', ''): 
     response.headers['Content-Encoding'] = 'gzip' 
     ret = gzip_body(ret) 
    else: 
     response.headers['Content-Encoding'] = 'identity' 
    return(ret) 


def write_gzip_header(): 
    header = '\037\213'  # magic header 
    header += '\010'   # compression method 
    header += '\0' 
    header += struct.pack("<L", long(time.time())) 
    header += '\002' 
    header += '\377' 
    return header 


def write_gzip_trailer(crc, size): 
    footer = struct.pack("<l", crc) 
    footer += struct.pack("<L", size & 0xFFFFFFFFL) 
    return footer 


def gzip_body(body, compress_level=6): 
    yield gzip_header() 
    crc = zlib.crc32("") 
    size = 0 
    zobj = zlib.compressobj(compress_level, 
          zlib.DEFLATED, -zlib.MAX_WBITS, 
          zlib.DEF_MEM_LEVEL, 0) 
    size += len(data) 
    crc = zlib.crc32(data, crc) 
    yield zobj.compress(data) 
    yield zobj.flush() 
    yield gzip_trailer(crc, size) 


run(host='localhost', port=6789, debug=True) 

그것은 조금 복잡하지만이 일을 : 여기

는 전체 코드입니다